<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml'/>
<!--}}}-->
Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {background:[[ColorPalette::PrimaryMid]];}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected{color:[[ColorPalette::PrimaryDark]];
	background:[[ColorPalette::TertiaryPale]];
	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}

#messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];}
#messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;}

.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.popup li.disabled {color:[[ColorPalette::TertiaryMid]];}
.popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;}
.popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];}
.selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];}
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button {border:none;}

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.sparkline {background:[[ColorPalette::PrimaryPale]]; border:0;}
.sparktick {background:[[ColorPalette::PrimaryDark]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];}

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

.viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
.viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];}

.viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:'alpha(opacity:60)';}
/*}}}*/
/*{{{*/
* html .tiddler {height:1%;}

body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
	#mainMenu .tiddlyLinkNonExisting,
	#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}

.header {position:relative;}
.header a:hover {background:transparent;}
.headerShadow {position:relative; padding:4.5em 0em 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0em 1em 1em; left:0px; top:0px;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0em 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 .3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard {padding:0.1em 1em 0em 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0em 0em 0em 0em; margin:0.4em 0em 0.2em 0em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0em 0em 0em 0em; margin:0.4em 0em 0.2em 0em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0em 0em 0em; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0em;}
.wizardFooter .status {padding:0em 0.4em 0em 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em 0.1em 0.2em;}

#messageArea {position:fixed; top:2em; right:0em; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
.messageToolbar {display:block; text-align:right; padding:0.2em 0.2em 0.2em 0.2em;}
#messageArea a {text-decoration:underline;}

.tiddlerPopupButton {padding:0.2em 0.2em 0.2em 0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em 1em 1em 1em; margin:0;}

.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0em;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tabset {padding:1em 0em 0em 0.5em;}
.tab {margin:0em 0em 0em 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0em 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler {padding:1em 1em 0em 1em;}

.missing .viewer,.missing .title {font-style:italic;}

.title {font-size:1.6em; font-weight:bold;}

.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation {padding:0.5em; margin:0.5em;}

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0em 0.25em; padding:0em 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0px 3px 0px 3px;}

.viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
.viewer code {font-size:1.2em; line-height:1.4em;}

.editor {font-size:1.1em;}
.editor input, .editor textarea {display:block; width:100%; font:inherit;}
.editorFooter {padding:0.25em 0em; font-size:.9em;}
.editorFooter .button {padding-top:0px; padding-bottom:0px;}

.fieldsetFix {border:0; padding:0; margin:1px 0px 1px 0px;}

.sparkline {line-height:1em;}
.sparktick {outline:0;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em 0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em 0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0em; right:0em;}
#backstageButton a {padding:0.1em 0.4em 0.1em 0.4em; margin:0.1em 0.1em 0.1em 0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; margin:0em 3em 0em 3em; padding:1em 1em 1em 1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em 0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none ! important;}
#displayArea {margin: 1em 1em 0em 1em;}
/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
noscript {display:none;}
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteTiddler'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->
To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:
* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* MainMenu: The menu (usually on the left)
* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These InterfaceOptions for customising TiddlyWiki are saved in your browser

Your username for signing your edits. Write it as a WikiWord (eg JoeBloggs)

<<option txtUserName>>
<<option chkSaveBackups>> SaveBackups
<<option chkAutoSave>> AutoSave
<<option chkRegExpSearch>> RegExpSearch
<<option chkCaseSensitiveSearch>> CaseSensitiveSearch
<<option chkAnimate>> EnableAnimations

----
Also see AdvancedOptions
<<importTiddlers>>
In Socialtext Unplugged, the selected pages of your Socialtext workspace are displayed as individual "tiddlers" on the page. When the mouse passes over a tiddler a short toolbar menu appears at the top right. Use the commands here to manipulate that particular tiddler: notably closing and editting it. (You can double click on a tiddler as a shortcut to directly enter edit mode).

Over on the right hand side of the window are commands that affect the entire page, in particular "close all" which can be useful to clear the decks when many tiddlers are open at once.

The user is encouraged to ensure that they can SaveChanges before embarking on widespread editing.
Welcome to Socialtext Unplugged. This is a specially designed web page that you can use to view and edit your Socialtext content without having to be online to your Socialtext server.

There are three steps to using Socialtext Unplugged:
* First, learn how to SaveChanges to your local hard drive. This keeps your work safe even if you close your browser or have to reboot your computer
* Secondly, find out how to BrowseAndEdit your content while it is unplugged
* Thirdly, when you can reconnect to your Socialtext server, you can SyncChanges to save your unplugged changes to the server so that other people can see them too

You should also check your system meets the SystemRequirements.
Socialtext Unplugged lets you browse and edit your content while you're offline. When you make a change you need to SaveChanges to save the change to your local hard drive, before later performing a SyncChanges to synchronise the change back to the server.

The procedure for SaveChanges is slightly different for different browsers:
* SavingOnInternetExplorer
* SavingOnFireFox
* SavingOnSafari
* SavingOnOpera
You can save changes with any version of FireFox, and also many other browsers in the FireFox family, such as Camino on the Mac and MiniMo on mobile devices. The procedure is:
# Click the button labelled 'save changes' over in the right hand sidebar
# If prompted with an "Internet Security" dialog as follows, click the checkbox labelled "Remember this decision" and then the "Allow" button
## "A script from "file://" is requesting enhanced capabilities that are UNSAFE and could be used to compromise your machine or data..."
# You should then see a message at the top right of the window saying "Main TiddlyWiki file saved"
If you accidentally //deny// permission instead, you may need to UnravelFireFoxPermissions.
You can save changes with Internet Explorer versions 6 and 7, but not the earlier versions. The procedure is:
# Click the button labelled 'save changes' over in the right hand sidebar
# If prompted as follows, click "Yes":
## "An ActiveX control on this page might be unsafe to interact with other parts of the page. Do you want to allow this interaction?"
# You should then see a message at the top right of the window saying "Main TiddlyWiki file saved"
Note that there is currently [[a bug|http://trac.tiddlywiki.org/tiddlywiki/ticket/39]] that prevents Internet Explorer from saving correctly if you have specified a backup directory in AdvancedOptions.
To SaveChanges on Opera, see the instructions for using the TiddlySaver Java applet.
To SaveChanges on Safari, see the instructions for using the TiddlySaver Java applet.
<<search>><<closeAll>><<permaview>><<newTiddler 'New Tiddler' fields:'server.host:"https://saturn.ffzg.hr%2C%20saturn.ffzg.hr:443" server.workspace:"rot13" wikiformat:socialtext'>><<newJournal 'DD MMM YYYY' fields:'server.host:"https://saturn.ffzg.hr%2C%20saturn.ffzg.hr:443" server.workspace:"rot13" wikiformat:socialtext'>><<saveChanges>><<backstage sync>><<slider chkSliderOptionsPanel OptionsPanel 'options »' 'Change TiddlyWiki advanced options'>>
Dobrica Pavlinušić's random unstructured stuff
Socialtext Unplugged
https://saturn.ffzg.hr/rot13/
[[SocialtextScreenStyle]]
[[SocialtextStyleOverrides]]
[[Styles HorizontalMainMenu]]
<<sync>>
@@The user interface for synchronization is not finalized@@
To synchronize your changes back to the Socialtext server:
# click on [[Sync]] in the right-hand sidebar
<<tabs txtMoreTab Orphans 'Orphaned tiddlers' TabMoreOrphans Shadowed 'Shadowed tiddlers' TabMoreShadowed>>
Under FireFox, you can run into problems if you accidentally click 'Deny' on the permission request dialog, and have selected //Remember this decision//.

To reverse the effects, first locate the file {{{prefs.js}}} in your FireFox profile directory. Under Windows you'll find it at something like {{{C:\Documents and Settings\Jeremy\Application Data\Mozilla\Firefox\Profiles\o3dhupu6.default\prefs.js}}}, where {{{Jeremy}}} is the name of your windows profile and {{{o3dhupu6}}} will be a similar string of gobbledegook. On the Mac it'll be at {{{~/Library/Application Support/Firefox/Profiles/o3dhupu6.default/prefs.js}}} and on most versions of Linux, at {{{~/.mozilla/firefox/o3dhupu6.default/prefs.js}}}.

Open the file in a text editor and find the line {{{user_pref("capability.principal.codebase.p0.denied", "UniversalXPConnect");}}} and simply replace the word {{{denied}}} with {{{granted}}}.
//(Thanks to JonScully for figuring out this fix)//
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler references > fields syncing jump'></div>
<div class='workspace' id='st-page-wiki-title' macro='view socialtext.workspace'></div>
<div class='title' id='st-page-titletext' macro='view title'></div>
<div class='subtitle'>
Created on <span macro='view created date [[MMM DD, 0hh:0mm]]'></span>.
Updated by <span macro='view modifier link'></span>
on <span macro='view modified date [[MMM DD, 0hh:0mm]]'></span></div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></span></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
/***
To use, add {{{[[Styles HorizontalMainMenu]]}}} to your StyleSheet tiddler.
See http://www.w3schools.com/css/css_colors.asp for a color chart.
***/
/*{{{*/
#mainMenu {position:relative;left:auto;width:auto;text-align:left;line-height:normal;padding 0em 1em 0em 1em;font-size:normal;}
#mainMenu br {display:none;}
#mainMenu {background:#336699;}
#mainMenu {padding:2px;}
#mainMenu .button, #mainMenu .tiddlyLink {padding-left:0.5em;padding-right:0.5em;color:white;font-size:115%;}

#displayArea {
	margin-top:0;margin-right:20em;margin-bottom:0;margin-left:1em;
	padding-top:.1em;padding-bottom:.1em;
}
/*}}}*/
|''Type:''|socialtext|
|''URL:''|https://saturn.ffzg.hr%2C%20saturn.ffzg.hr:443 |
|''Workspace:''|rot13|
|''WorkspaceList:''||
|''Description:''|Dobrica Pavlinušić's random unstructured stuff|
The TiddlySaver Java applet allows TiddlyWiki from a {{{file://}}} URL to save changes Safari, Opera and other browsers.

It is a small file named [["TiddlySaver.jar"|TiddlySaver.jar]] that must be placed in the same directory as your TiddlyWiki file. Before you can use it, you need to give it the necessary privileges by editting your {{{.java.policy}}} file.

For Windows, the file will be at {{{C:\Documents and Settings\your-user-name\.java.policy}}}. Add the following lines (substituting the directory of your TiddlyWiki file as appropriate):
{{{
grant codeBase "file:${user.home}/My Documents/tiddlywiki-folder/*" {
  permission java.io.FilePermission "${user.home}${/}My Documents${/}tiddlywiki-folder${/}*", "read,write";
};
}}}
On Mac OS X, the file is found at {{{/Users/your-user-name/.java.policy}}}:
{{{
grant codeBase "file:${user.home}/Documents/tiddlywiki-folder/*" {
  permission java.io.FilePermission "${user.home}${/}Documents${/}tiddlywiki-folder${/}*", "read,write";
};
}}}
It can be tricky creating files whose name starts with a period, so you can use this [[pre-built .java.policy file|.java.policy]]. The same file is suitable for Macs too, just edit it and delete the "My " bit, leaving just "Documents". Make sure you save it in the right place for each operating system!

If you have trouble setting up the permissions correctly, you can try granting broader permissions to the applet like this:

{{{
grant codeBase "file://localhost/home/users/Desktop/
TiddlySaver.jar"
 { permission java.security.AllPermission; };
}}}

Note that there is currently [[a bug|http://trac.tiddlywiki.org/ticket/172]] that prevents TiddlySaver from working if you have specified a backup directory in AdvancedOptions.
/***
|''Name:''|SocialtextLocaleOverrides|
|''Description:''|Text changes for Socialtext|
***/

//{{{
merge(config.views.wikified.tag,{
	labelNoTags: "No Tags",
	labelTags: "Tags"});

merge(config.commands.references,{
	text: "incoming links",
	tooltip: "Show tiddlers that link to this one",
	popupNone: "No incoming links"});
//}}}
/***
|''Name:''|SocialtextTweaksPlugin|
|''Description:''|Allows changes to be synchronised with a Socialtext server|
|''Source:''|http://stunplugged.tiddlywiki.com/#SocialtextTweaksPlugin|
|''Author:''|JeremyRuston (jeremy (at) osmosoft (dot) com)|
|''Version:''|1.0.2|
|''Date:''|Jun 15, 2006|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev|
|''License:''|[[BSD open source license]]|
|''~CoreVersion:''|2.2|

Make minor configuration tweaks specific to Socialtext Unplugged
***/

//{{{
// Ensure that the SocialtextTweaksPlugin is only installed once.
if(!version.extensions.SocialtextTweaksPlugin) {
version.extensions.SocialtextTweaksPlugin = {installed:true};
// Check version number of core code
if(version.major < 2 || (version.major == 2 && version.minor < 2))
	{alertAndThrow("SocialtextTweaksPlugin requires TiddlyWiki 2.2 or later.");}

merge(config.defaultCustomFields,{
	wikiformat:'socialtext',
	'server.host':'https://saturn.ffzg.hr%2C%20saturn.ffzg.hr:443'
});

config.options.chkSinglePageMode = true;
config.options.chkEnableAnimations = true;

} // end of "install only once"
//}}}
/***
|''Name:''|SocialtextFormatterPlugin|
|''Description:''|Allows Tiddlers to use [[Socialtext|http://www.socialtext.com/]] text formatting|
|''Author:''|Martin Budden (mjbudden (at) gmail (dot) com)|
|''Source:''|http://www.martinswiki.com/#SocialtextFormatterPlugin|
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/MartinBudden/formatters/SocialtextFormatterPlugin.js|
|''Version:''|0.9.4|
|''Date:''|Jan 21, 2007|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev|
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|''~CoreVersion:''|2.1.0|

This is the SocialtextFormatterPlugin, which allows you to insert Socialtext formated text into a TiddlyWiki.

The aim is not to fully emulate Socialtext, but to allow you to work with Socialtext content off-line and then resync the content with your Socialtext wiki later on, with the expectation that only minor edits will be required.

To use Socialtext format in a Tiddler, tag the Tiddler with SocialtextFormat or set the tiddler's {{{wikiformat}}} extended field to {{{socialtext}}}

Please report any defects you find at http://groups.google.co.uk/group/TiddlyWikiDev
***/

//{{{
// Ensure that the SocialtextFormatter Plugin is only installed once.
if(!version.extensions.SocialtextFormatterPlugin) {
version.extensions.SocialtextFormatterPlugin = {installed:true};

if(version.major < 2 || (version.major == 2 && version.minor < 1))
	{alertAndThrow('SocialtextFormatterPlugin requires TiddlyWiki 2.1 or later.');}

SocialtextFormatter = {}; // 'namespace' for local functions

wikify = function(source,output,highlightRegExp,tiddler)
{
	if(source && source != '') {
		var w = new Wikifier(source,getParser(tiddler),highlightRegExp,tiddler);
		var out = output;
		if(tiddler && (tiddler.isTagged(config.parsers.socialtextFormatter.formatTag) || (tiddler.fields.wikiformat==config.parsers.socialtextFormatter.format)) ) {
			var d1 = createTiddlyElement(output,'div','content-display-body','content-section-visible');
			var d2 = createTiddlyElement(d1,'div','wikipage');
			out = createTiddlyElement(d2,'div',null,'wiki');
		}
		var time1,time0 = new Date();
		w.subWikifyUnterm(out);
		if(tiddler && config.options.chkDisplayInstrumentation) {
			time1 = new Date();
			var t = tiddler ? tiddler.title : source.substr(0,10);
			displayMessage("Wikify '"+t+"' in " + (time1-time0) + " ms");
		}
	}
};

stDebug = function(out,str)
{
	createTiddlyText(out,str.replace(/\n/mg,'\\n').replace(/\r/mg,'RR'));
	createTiddlyElement(out,'br');
};

SocialtextFormatter.Tiddler_changed = Tiddler.prototype.changed;
Tiddler.prototype.changed = function()
{
	if((this.fields.wikiformat==config.parsers.socialtextFormatter.format) || this.isTagged(config.parsers.socialtextFormatter.formatTag)) {
		// update the links array, by checking for Socialtext format links
		this.links = [];
		var tiddlerLinkRegExp = /(?:\"(.*?)\" ?)?\[([^\]]*?)\]/mg;
		tiddlerLinkRegExp.lastIndex = 0;
		var match = tiddlerLinkRegExp.exec(this.text);
		while(match) {
			var link = match[2];
			this.links.pushUnique(link);
			match = tiddlerLinkRegExp.exec(this.text);
		}
	}/* else {
		return SocialtextFormatter.Tiddler_changed.apply(this,arguments);
	}*/
	this.linksUpdated = true;
};

SocialtextFormatter.wafl = function(w)
{
	this.lookaheadRegExp.lastIndex = w.matchStart;
	var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
	if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
		var lm2 = lookaheadMatch[2];
		switch(lookaheadMatch[1]) {
		case 'image':
			var img = createTiddlyElement(w.output,'img');
			img.src = w.tiddler.title + '/' + lm2;
			createTiddlyText(img,lm2);
			break;
		case 'file':
			var s = createTiddlyElement(w.output,'span',null,'nlw_phrase');
			var a = createTiddlyElement(s,'a');
			a.href = w.tiddler.title + '/' + lm2;
			createTiddlyText(a,lm2);
			break;
		case 'link':
			s = createTiddlyElement(w.output,'span',null,'nlw_phrase');
			a = createTiddlyElement(s,'a');
			var t = w.tiddler ? w.tiddler.title + ':' : '';
			a.setAttribute('href','#' + t + lm2);
			a.title = 'section link';
			createTiddlyText(a,lm2);
			break;
		case 'weblog':
			s = createTiddlyElement(w.output,'span',null,'nlw_phrase');
			var text = lm2;
			var link = 'Weblog: ' + lm2;
			createTiddlyText(createTiddlyLink(s,link,false,null,w.isStatic),text);
			break;
		case 'section':
			a = createTiddlyElement(w.output,'a');// drop anchor
			t = w.tiddler ? w.tiddler.title + ':' : '';
			a.setAttribute('name',t + lm2);
			break;
		case 'date':
			createTiddlyText(w.output,lm2);
			break;
		case 'user':
			var oldSource = w.source;
			w.source = lm2;
			w.nextMatch = 0;
			w.subWikifyUnterm(w.output);
			w.source = oldSource;
			break;
// Shortcut expansions - not strictly syntax
		case 'google':
			s = createTiddlyElement(w.output,'span',null,'nlw_phrase');
			a = createExternalLink(s,'http://www.google.com/search?q='+lm2);
			createTiddlyText(a,lm2);
			break;
		case 'fedex':
			s = createTiddlyElement(w.output,'span',null,'nlw_phrase');
			a = createExternalLink(s,'http://www.fedex.com/Tracking?tracknumbers='+lm2);
			createTiddlyText(a,lm2);
			break;
		case 'map':
			s = createTiddlyElement(w.output,'span',null,'nlw_phrase');
			a = createExternalLink(s,'http://maps.google.com/maps?q='+lm2);
			createTiddlyText(a,lm2);
			break;
		case 'wikipedia':
			s = createTiddlyElement(w.output,'span',null,'nlw_phrase');
			a = createExternalLink(s,'http://en.wikipedia.org/wiki/'+lm2);
			createTiddlyText(a,lm2);
			break;
		case 'rt':
			s = createTiddlyElement(w.output,'span',null,'nlw_phrase');
			a = createExternalLink(s,'http://rt.socialtext.net/Ticket/Display.html?id='+lm2);
			createTiddlyText(a,lm2);
			break;
		case 'stcal':
			s = createTiddlyElement(w.output,'span',null,'nlw_phrase');
			a = createExternalLink(s,'https://calendar.socialtext.net:445/view_t.php?timeb=1&id=3&date='+lm2);
			createTiddlyText(a,lm2);
			break;
		case 'svn':
			s = createTiddlyElement(w.output,'span',null,'nlw_phrase');
			a = createExternalLink(s,'https://repo.socialtext.net/listing.php?rev='+lm2+'sc=1');
			createTiddlyText(a,lm2);
			break;
		default:
			w.outputText(w.output,w.matchStart,w.nextMatch);
			return;
		}
		w.nextMatch = this.lookaheadRegExp.lastIndex;
	} else {
		w.outputText(w.output,w.matchStart,w.nextMatch);
	}
};

SocialtextFormatter.presence = function(w)
{
	this.lookaheadRegExp.lastIndex = w.matchStart;
	var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
	if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
		var p = lookaheadMatch[1];
		var text = lookaheadMatch[2];
		var link;
		var src;
		if(p=='aim') {
			link = 'aim:goim?screenname=' + text + '&message=hello';
			src = 'http://big.oscar.aol.com/sleepleft?on_url=http://www.aim.com/remote/gr/MNB_online.gif&amp;off_url=http://www.aim.com/remote/gr/MNB_offline.gif';
		} else if(p=='yahoo'||p=='ymsgr') {
			link = 'ymsgr:sendIM?'+text;
			src = 'http://opi.yahoo.com/online?u=chrislondonbridge&f=.gif';
		} else if(p=='skype'||p=='callto') {
			link = 'callto:'+text;
			src = 'http://goodies.skype.com/graphics/skypeme_btn_small_green.gif';
		} else if(p=='asap') {
			link = 'http://asap2.convoq.com/AsapLinks/Meet.aspx?l='+text;
			src = 'http://asap2.convoq.com/AsapLinks/Presence.aspx?l='+text;
		}
		var s = createTiddlyElement(w.output,'span',null,'nlw_phrase');
		var a = createExternalLink(s,link);
		var img = createTiddlyElement(a,'img');
		createTiddlyText(a,text);
		img.src = src;
		img.border='0';
		img.alt = '(' + lookaheadMatch[1] + ')';
		if(p=='aim') {
			img.width='11'; img.height='13';
		}
		w.nextMatch = this.lookaheadRegExp.lastIndex;
	}
};

config.formatterHelpers.singleCharFormat = function(w)
{
	this.lookaheadRegExp.lastIndex = w.matchStart;
	var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
	if(lookaheadMatch && lookaheadMatch.index == w.matchStart && lookaheadMatch[0].substr(lookaheadMatch[0].length-2,1) != ' ') {
		w.subWikifyTerm(createTiddlyElement(w.output,this.element),this.termRegExp);
	} else {
		w.outputText(w.output,w.matchStart,w.nextMatch);
	}
};

config.socialtext = {};
config.socialtext.formatters = [
{
	name: 'socialtextHeading',
	match: '^\\^{1,6} ?',
	termRegExp: /(\n+)/mg,
	handler: function(w)
	{
		var len = w.matchText.trim().length;
		var e = createTiddlyElement(w.output,'h' + len);
		var a = createTiddlyElement(e,'a');// drop anchor
		var t = w.tiddler ? w.tiddler.title + ':' : '';
		len = w.source.substr(w.nextMatch).indexOf('\n');
		a.setAttribute('name',t+w.source.substr(w.nextMatch,len));
		w.subWikifyTerm(e,this.termRegExp);
	}
},

{
	name: 'socialtextTable',
	match: '^\\|(?:(?:.|\n)*)\\|$',
	lookaheadRegExp: /^\|(?:(?:.|\n)*)\|$/mg,
	cellRegExp: /(?:\|(?:[^\|]*)\|)(\n|$)?/mg,
	cellTermRegExp: /((?:\x20*)\|)/mg,
	handler: function(w)
	{
		var table = createTiddlyElement(w.output,'table');
		var rowContainer = createTiddlyElement(table,'tbody');
		var prevColumns = [];
		w.nextMatch = w.matchStart;
		this.lookaheadRegExp.lastIndex = w.nextMatch;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		while(lookaheadMatch && lookaheadMatch.index == w.nextMatch) {
			var r = this.rowHandler(w,createTiddlyElement(rowContainer,'tr'),prevColumns);
			if(!r) {
				w.nextMatch++;
				break;
			}
			this.lookaheadRegExp.lastIndex = w.nextMatch;
			lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		}
	},
	rowHandler: function(w,e,prevColumns)
	{
		this.cellRegExp.lastIndex = w.nextMatch;
		var cellMatch = this.cellRegExp.exec(w.source);
		while(cellMatch && cellMatch.index == w.nextMatch) {
			w.nextMatch++;
			var cell = createTiddlyElement(e,'td');
			w.subWikifyTerm(cell,this.cellTermRegExp);
			if(cellMatch[1]) {
				// End of row
				w.nextMatch = this.cellRegExp.lastIndex;
				return true;
			}
			// Cell
			w.nextMatch--;
			this.cellRegExp.lastIndex = w.nextMatch;
			cellMatch = this.cellRegExp.exec(w.source);
		}
		return false;
	}
},

{
	name: 'socialtextList',
	match: '^[\\*#]+ ',
	lookaheadRegExp: /^([\*#])+ /mg,
	termRegExp: /(\n+)/mg,
	handler: function(w)
	{
		var stack = [w.output];
		var currLevel = 0, currType = null;
		var itemType = 'li';
		w.nextMatch = w.matchStart;
		this.lookaheadRegExp.lastIndex = w.nextMatch;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		while(lookaheadMatch && lookaheadMatch.index == w.nextMatch) {
			var listType = lookaheadMatch[1] == '*' ? 'ul' : 'ol';
			var listLevel = lookaheadMatch[0].length;
			w.nextMatch += listLevel;
			if(listLevel > currLevel) {
				for(var i=currLevel; i<listLevel; i++) {
					stack.push(createTiddlyElement(stack[stack.length-1],listType));
				}
			} else if(listLevel < currLevel) {
				for(i=currLevel; i>listLevel; i--) {
					stack.pop();
				}
			} else if(listLevel == currLevel && listType != currType) {
				stack.pop();
				stack.push(createTiddlyElement(stack[stack.length-1],listType));
			}
			currLevel = listLevel;
			currType = listType;
			var e = createTiddlyElement(stack[stack.length-1],itemType);
			w.subWikifyTerm(e,this.termRegExp);
			this.lookaheadRegExp.lastIndex = w.nextMatch;
			lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		}
	}
},

{
	name: 'socialtextQuoteByLine',
	match: '^>+',
	lookaheadRegExp: /^>+/mg,
	termRegExp: /(\n)/mg,
	element: 'blockquote',
	handler: function(w)
	{
		var stack = [w.output];
		var currLevel = 0;
		var newLevel = w.matchLength;
		var i;
		do {
			if(newLevel > currLevel) {
				for(i=currLevel; i<newLevel; i++) {
					stack.push(createTiddlyElement(stack[stack.length-1],this.element));
				}
			} else if(newLevel < currLevel) {
				for(i=currLevel; i>newLevel; i--) {
					stack.pop();
				}
			}
			currLevel = newLevel;
			w.subWikifyTerm(stack[stack.length-1],this.termRegExp);
			createTiddlyElement(stack[stack.length-1],'br');
			this.lookaheadRegExp.lastIndex = w.nextMatch;
			var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
			var matched = lookaheadMatch && lookaheadMatch.index == w.nextMatch;
			if(matched) {
				newLevel = lookaheadMatch[0].length;
				w.nextMatch += newLevel;
			}
		} while(matched);
	}
},

{
	name: 'socialtextRule',
	match: '^----+$\\n+',
	handler: function(w)
	{
		createTiddlyElement(w.output,'hr');
	}
},

{
	name: 'socialtextPreformatted',
	match: '^\\.pre\\s*\\n',
	lookaheadRegExp: /^.pre\s*\n((?:.|\n)*?)\n.pre\s*\n/mg,
	element: 'pre',
	handler: config.formatterHelpers.enclosedTextHelper
},

{
	name: 'socialtextHtml',
	match: '^\\.html',
	lookaheadRegExp: /\.html((?:.|\n)*?)\.html/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			createTiddlyElement(w.output,'span').innerHTML = lookaheadMatch[1];
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
},

{
	name: 'macro',
	match: '<<',
	lookaheadRegExp: /<<([^>\s]+)(?:\s*)((?:[^>]|(?:>(?!>)))*)>>/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart && lookaheadMatch[1]) {
			w.nextMatch = this.lookaheadRegExp.lastIndex;
			invokeMacro(w.output,lookaheadMatch[1],lookaheadMatch[2],w,w.tiddler);
		}
	}
},

{
	name: 'socialtextExplicitLink',
	match: '(?:".*?" ?)?\\[',
	lookaheadRegExp: /(?:\"(.*?)\" ?)?\[([^\]]*?)\]/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var link = lookaheadMatch[2];
			var text = lookaheadMatch[1] ? lookaheadMatch[1] : link;
			createTiddlyText(createTiddlyLink(w.output,link,false,null,w.isStatic,w.tiddler),text);
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
},

{
	name: 'socialtextExternalLink',
	match: '(?:".*?" ?)?<[a-z]{2,8}:',
	lookaheadRegExp: /(?:\"(.*?)\" ?)?<([a-z]{2,8}:.*?)>/mg,
	imgRegExp: /\.(?:gif|ico|jpg|png)/g,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var link = lookaheadMatch[2];
			var text = lookaheadMatch[1] ? lookaheadMatch[1] : link;
			this.imgRegExp.lastIndex = 0;
			if(this.imgRegExp.exec(link)) {
				var img = createTiddlyElement(w.output,'img');
				if(lookaheadMatch[1]) {
					img.title = text;
				}
				img.alt = text;
				img.src = link;
			} else {
				createTiddlyText(createExternalLink(w.output,link),text);
			}
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
},

{
	name: 'socialtextUrlLink',
	match: config.textPrimitives.urlPattern,
	handler: function(w)
	{
		w.outputText(createExternalLink(w.output,w.matchText),w.matchStart,w.nextMatch);
	}
},

{
	name: 'socialtextBold',
	match: '\\*(?![\\s\\*])',
	lookaheadRegExp: /\*(?!\s)(?:.*?)(?!\s)\*(?=[$\s\|\._\-,])/mg,
	termRegExp: /((?!\s)\*(?=[$\s\|\.\-_,]))/mg,
	element: 'strong',
	handler: config.formatterHelpers.singleCharFormat
},

{
	name: 'socialtextItalic',
	match: '_(?![\\s_])',
	lookaheadRegExp: /_(?!\s)(?:.*?)(?!\s)_(?=[$\s\|\.\*\-,])/mg,
	termRegExp: /((?!\s)_(?=[$\s\|\.\*\-,]))/mg,
	element: 'em',
	handler: config.formatterHelpers.singleCharFormat
},

{
	name: 'socialtextStrike',
	match: '-(?![\\s\\-])',
	lookaheadRegExp: /-(?!\s)(?:.*?)(?!\s)-(?=[$\s\|\.\*_,])/mg,
	termRegExp: /((?!\s)-(?=[$\s\|\.\*_,]))/mg,
	element: 'del',
	handler: config.formatterHelpers.singleCharFormat
},

{
	name: 'socialtextMonoSpaced',
	match: '`(?![\\s`])',
	lookaheadRegExp: /`(?!\s)(?:.*?)(?!\s)`(?=[$\s\.\*\-_,])/mg,
	termRegExp: /((?!\s)`(?=[$\s\.\*\-_,]))/mg,
	element: 'tt',
	handler: config.formatterHelpers.singleCharFormat
},

{
	name: 'socialtextParagraph',
	match: '\\n{2,}',
	handler: function(w)
	{
		createTiddlyElement(w.output,'p');
	}
},

{
	name: 'socialtextLineBreak',
	match: '\\n',
	handler: function(w)
	{
		createTiddlyElement(w.output,'br');
	}
},

{
	name: 'socialtextNoWiki',
	match: '\\{\\{',
	lookaheadRegExp: /\{\{((?:.|\n)*?)\}\}/mg,
	element: 'span',
	handler: config.formatterHelpers.enclosedTextHelper
},

{
	name: 'socialtextTrademark',
	match: '\\{tm\\}',
	handler: function(w)
	{
		createTiddlyElement(w.output,'span').innerHTML = '&trade;';
	}
},

{
	name: 'socialtextWafl',
	match: '\\{(?:[a-z]{2,16}): ?.*?\\}',
	lookaheadRegExp: /\{([a-z]{2,16}): ?(.*?)\}/mg,
	handler: SocialtextFormatter.wafl
},

{
	name: 'socialtextPresence',
	match: '(?:aim|yahoo|ymsgr|skype|callto|asap):\\w+',
	lookaheadRegExp: /(aim|yahoo|ymsgr|skype|callto|asap):(\w+)/mg,
	handler: SocialtextFormatter.presence
},

{
	name: 'socialtextMailTo',
	match: '[\\w\.]+@[\\w]+\.[\\w\.]+',
	lookaheadRegExp: /([\w\.]+@[\w]+\.[\w\.]+)/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var text = lookaheadMatch[1];
			createTiddlyText(createExternalLink(w.output,'mailto:'+text),text);
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
},

{
	name: 'socialtextHtmlEntitiesEncoding',
	match: '&#?[a-zA-Z0-9]{2,8};',
	handler: function(w)
	{
		createTiddlyElement(w.output,'span').innerHTML = w.matchText;
	}
}
];

config.parsers.socialtextFormatter = new Formatter(config.socialtext.formatters);
config.parsers.socialtextFormatter.format = 'socialtext';
config.parsers.socialtextFormatter.formatTag = 'SocialtextFormat';

} // end of 'install only once'
//}}}
/***
|''Name:''|SocialtextAdaptorPlugin|
|''Description:''|Adaptor for moving and converting data to and from Socialtext Wikis|
|''Author:''|Martin Budden (mjbudden (at) gmail (dot) com) and JeremyRuston (jeremy (at) osmosoft (dot) com)|
|''Source:''|http://www.martinswiki.com/#SocialtextAdaptorPlugin|
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/MartinBudden/adaptors/SocialtextAdaptorPlugin.js|
|''Version:''|0.5.1|
|''Date:''|Feb 25, 2007|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev|
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|''~CoreVersion:''|2.2.0|

Socialtext REST documentation is at:
http://www.eu.socialtext.net/st-rest-docs/index.cgi?socialtext_rest_documentation

***/

//{{{
if(!version.extensions.SocialtextAdaptorPlugin) {
version.extensions.SocialtextAdaptorPlugin = {installed:true};

function SocialtextAdaptor()
{
	this.host = null;
	this.workspace = null;
	return this;
}

SocialtextAdaptor.mimeType = 'text/x.socialtext-wiki';
SocialtextAdaptor.serverType = 'socialtext';
SocialtextAdaptor.serverParsingErrorMessage = "Error parsing result from server";
SocialtextAdaptor.errorInFunctionMessage = "Error in function SocialtextAdaptor.%0";

SocialtextAdaptor.prototype.setContext = function(context,userParams,callback)
{
	if(!context) context = {};
	context.userParams = userParams;
	if(callback) context.callback = callback;
	context.adaptor = this;
	if(!context.host)
		context.host = this.host;
	if(!context.workspace && this.workspace)
		context.workspace = this.workspace;
	return context;
};

SocialtextAdaptor.doHttpGET = function(uri,callback,params,headers,data,contentType,username,password)
{
	return doHttp('GET',uri,data,contentType,username,password,callback,params,headers);
};

SocialtextAdaptor.doHttpPOST = function(uri,callback,params,headers,data,contentType,username,password)
{
	return doHttp('POST',uri,data,contentType,username,password,callback,params,headers);
};

SocialtextAdaptor.fullHostName = function(host)
{
	if(!host)
		return '';
	if(!host.match(/:\/\//))
		host = 'http://' + host;
	if(host.substr(host.length-1) != '/')
		host = host + '/';
	return host;
};

SocialtextAdaptor.minHostName = function(host)
{
	return host ? host.replace(/^http:\/\//,'').replace(/\/$/,'') : '';
};

// Convert a page title to the normalized form used in uris
SocialtextAdaptor.normalizedTitle = function(title)
{
	var n = title.toLowerCase();
	n = n.replace(/\s/g,'_').replace(/\//g,'_').replace(/\./g,'_').replace(/:/g,'').replace(/\?/g,'');
	if(n.charAt(0)=='_')
		n = n.substr(1);
	return String(n);
};

// Convert a Socialtext date in YYYY-MM-DD hh:mm format into a JavaScript Date object
SocialtextAdaptor.dateFromEditTime = function(editTime)
{
	var dt = editTime;
	return new Date(Date.UTC(dt.substr(0,4),dt.substr(5,2)-1,dt.substr(8,2),dt.substr(11,2),dt.substr(14,2)));
};

SocialtextAdaptor.prototype.openHost = function(host,context,userParams,callback)
{
	this.host = SocialtextAdaptor.fullHostName(host);
	context = this.setContext(context,userParams,callback);
	if(context.callback) {
		context.status = true;
		window.setTimeout(function() {callback(context,userParams);},0);
	}
	return true;
};

SocialtextAdaptor.prototype.openWorkspace = function(workspace,context,userParams,callback)
{
	this.workspace = workspace;
	context = this.setContext(context,userParams,callback);
	if(context.callback) {
		context.status = true;
		window.setTimeout(function() {callback(context,userParams);},0);
	}
	return true;
};


SocialtextAdaptor.prototype.getWorkspaceList = function(context,userParams,callback)
{
	context = this.setContext(context,userParams,callback);
	var uriTemplate = '%0data/workspaces';
	var uri = uriTemplate.format([context.host]);
	var req = SocialtextAdaptor.doHttpGET(uri,SocialtextAdaptor.getWorkspaceListCallback,context,{'accept':'application/json'});
	return typeof req == 'string' ? req : true;
};

SocialtextAdaptor.getWorkspaceListCallback = function(status,context,responseText,uri,xhr)
{
	context.status = false;
	context.statusText = SocialtextAdaptor.errorInFunctionMessage.format(['getWorkspaceListCallback']);
	if(status) {
		try {
			eval('var info=' + responseText);
		} catch (ex) {
			context.statusText = exceptionText(ex,SocialtextAdaptor.serverParsingErrorMessage);
			if(context.callback)
				context.callback(context,context.userParams);
			return;
		}
		var list = [];
		for(var i=0; i<info.length; i++) {
			var item = {
				title:info[i].title,
				name:info[i].name,
				modified:SocialtextAdaptor.dateFromEditTime(info[i].modified_time)
				};
			list.push(item);
		}
		context.workspaces = list;
		context.status = true;
	} else {
		context.statusText = xhr.statusText;
	}
	if(context.callback)
		context.callback(context,context.userParams);
};

SocialtextAdaptor.prototype.getTiddlerList = function(context,userParams,callback)
{
	context = this.setContext(context,userParams,callback);
	var uriTemplate = '%0data/workspaces/%1/pages?order=newest';//!! ? or ;
	var uri = uriTemplate.format([context.host,context.workspace]);
	var req = SocialtextAdaptor.doHttpGET(uri,SocialtextAdaptor.getTiddlerListCallback,context,{'accept':'application/json'});
	return typeof req == 'string' ? req : true;
};


SocialtextAdaptor.getTiddlerListCallback = function(status,context,responseText,uri,xhr)
{
	context.status = false;
	context.statusText = SocialtextAdaptor.errorInFunctionMessage.format(['getTiddlerListCallback']);
	if(status) {
		try {
			eval('var info=' + responseText);
		} catch (ex) {
			context.statusText = exceptionText(ex,SocialtextAdaptor.serverParsingErrorMessage);
			if(context.callback)
				context.callback(context,context.userParams);
			return;
		}
		var list = [];
		for(var i=0; i<info.length; i++) {
			var tiddler = new Tiddler(info[i].name);
			tiddler.modified = SocialtextAdaptor.dateFromEditTime(info[i].last_edit_time);
			tiddler.modifier = info[i].last_editor;
			tiddler.tags = info[i].tags;
			tiddler.fields['server.page.id'] = info[i].page_id;
			tiddler.fields['server.page.name'] = info[i].name;
			tiddler.fields['server.page.revision'] = String(info[i].revision_id);
			list.push(tiddler);
		}
		context.tiddlers = list;
		context.status = true;
	} else {
		context.statusText = xhr.statusText;
	}
	if(context.callback)
		context.callback(context,context.userParams);
};

SocialtextAdaptor.prototype.generateTiddlerInfo = function(tiddler)
{
	var info = {};
	var host = this && this.host ? this.host : SocialtextAdaptor.fullHostName(tiddler.fields['server.host']);
	var workspace = this && this.workspace ? this.workspace : tiddler.fields['server.workspace'];
	uriTemplate = '%0%1/index.cgi?%2';
	info.uri = uriTemplate.format([host,workspace,SocialtextAdaptor.normalizedTitle(tiddler.title)]);
	return info;
};

SocialtextAdaptor.prototype.getTiddler = function(title,context,userParams,callback)
{
	return this.getTiddlerRevision(title,null,context,userParams,callback);
};

SocialtextAdaptor.prototype.getTiddlerRevision = function(title,revision,context,userParams,callback)
{
	context = this.setContext(context,userParams,callback);

	// request the page in json format to get the page attributes
	if(revision) {
		var uriTemplate = '%0data/workspaces/%1/pages/%2/revisions/%3';
		context.revision = revision;
	} else {
		uriTemplate = '%0data/workspaces/%1/pages/%2';
		context.revision = null;
	}
	uri = uriTemplate.format([context.host,context.workspace,SocialtextAdaptor.normalizedTitle(title),revision]);

	context.tiddler = new Tiddler(title);
	context.tiddler.fields.wikiformat = 'socialtext';
	context.tiddler.fields['server.host'] = SocialtextAdaptor.minHostName(context.host);
	context.tiddler.fields['server.workspace'] = context.workspace;
	var req = SocialtextAdaptor.doHttpGET(uri,SocialtextAdaptor.getTiddlerCallback,context,{'accept':'application/json'});
	return typeof req == 'string' ? req : true;
};


SocialtextAdaptor.getTiddlerCallback = function(status,context,responseText,uri,xhr)
{
	context.status = false;
	context.statusText = SocialtextAdaptor.errorInFunctionMessage.format(['getTiddlerCallback']);
	if(status) {
		try {
			eval('var info=' + responseText);
			context.tiddler.tags = info.tags;
			context.tiddler.fields['server.page.id'] = info.page_id;
			context.tiddler.fields['server.page.name'] = info.name;
			context.tiddler.fields['server.page.revision'] = String(info.revision_id);
			context.tiddler.modifier = info.last_editor;
			context.tiddler.modified = SocialtextAdaptor.dateFromEditTime(info.last_edit_time);
		} catch (ex) {
			context.statusText = exceptionText(ex,SocialtextAdaptor.serverParsingErrorMessage);
			if(context.callback)
				context.callback(context,context.userParams);
			return;
		}
		context.status = true;
	} else {
		context.statusText = xhr.statusText;
		if(context.callback)
			context.callback(context,context.userParams);
		return;
	}
	var uriTemplate = context.revision ? '%0data/workspaces/%1/pages/%2/revisions/%3' : '%0data/workspaces/%1/pages/%2';
	var host = SocialtextAdaptor.fullHostName(context.tiddler.fields['server.host']);
	var workspace = context.workspace ? context.workspace : context.tiddler.fields['server.workspace'];
	uri = uriTemplate.format([host,workspace,SocialtextAdaptor.normalizedTitle(context.tiddler.title),context.revision]);
	var req = SocialtextAdaptor.doHttpGET(uri,SocialtextAdaptor.getTiddlerCallback2,context,{'accept':SocialtextAdaptor.mimeType});
};

SocialtextAdaptor.getTiddlerCallback2 = function(status,context,responseText,uri,xhr)
{
	context.tiddler.text = responseText;
	if(status) {
		context.status = true;
	} else {
		context.status = false;
		context.statusText = xhr.statusText;
	}
	if(context.callback)
		context.callback(context,context.userParams);
};

SocialtextAdaptor.prototype.getTiddlerRevisionList = function(title,limit,context,userParams,callback)
{
	context = this.setContext(context,userParams,callback);

	var uriTemplate = '%0data/workspaces/%1/pages/%2/revisions?accept=application/json';
	if(!limit)
		limit = 5;
	var uri = uriTemplate.format([context.host,context.workspace,SocialtextAdaptor.normalizedTitle(title),limit]);

	var req = SocialtextAdaptor.doHttpGET(uri,SocialtextAdaptor.getTiddlerRevisionListCallback,context);
	return typeof req == 'string' ? req : true;
};

SocialtextAdaptor.getTiddlerRevisionListCallback = function(status,context,responseText,uri,xhr)
{
	context.status = false;
	if(status) {
		var content = null;
		try {
			eval('var info=' + responseText);
		} catch (ex) {
			context.statusText = exceptionText(ex,SocialtextAdaptor.serverParsingErrorMessage);
			if(context.callback)
				context.callback(context,context.userParams);
			return;
		}
		list = [];
		for(var i=0; i<info.length; i++) {
			var tiddler = new Tiddler(info[i].name);
			tiddler.modified = SocialtextAdaptor.dateFromEditTime(info[i].last_edit_time);
			tiddler.modifier = info[i].last_editor;
			tiddler.tags = info[i].tags;
			tiddler.fields['server.page.id'] = info[i].page_id;
			tiddler.fields['server.page.name'] = info[i].name;
			tiddler.fields['server.page.revision'] = info[i].revision_id;
			list.push(tiddler);
		}
		var sortField = 'server.page.revision';
		list.sort(function(a,b) {return a.fields[sortField] < b.fields[sortField] ? +1 : (a.fields[sortField] == b.fields[sortField] ? 0 : -1);});
		context.revisions = list;
		context.status = true;
	} else {
		context.statusText = xhr.statusText;
	}
	if(context.callback)
		context.callback(context,context.userParams);
};

SocialtextAdaptor.prototype.putTiddler = function(tiddler,context,userParams,callback)
{
	context = this.setContext(context,userParams,callback);
	context.tiddler = tiddler;
	context.title = tiddler.title;
	var uriTemplate = '%0data/workspaces/%1/pages/%2';
	var host = context.host ? context.host : SocialtextAdaptor.fullHostName(tiddler.fields['server.host']);
	var workspace = context.workspace ? context.workspace : tiddler.fields['server.workspace'];
	var uri = uriTemplate.format([host,workspace,tiddler.title,tiddler.text]);
	//var req = doHttp('POST',uri,tiddler.text,SocialtextAdaptor.mimeType,null,null,SocialtextAdaptor.putTiddlerCallback,context,{"X-Http-Method": "PUT"});
	var req = SocialtextAdaptor.doHttpPOST(uri,SocialtextAdaptor.putTiddlerCallback,context,{"X-Http-Method": "PUT"},tiddler.text,SocialtextAdaptor.mimeType);
	return typeof req == 'string' ? req : true;
};

SocialtextAdaptor.putTiddlerCallback = function(status,context,responseText,uri,xhr)
{
	if(status) {
		context.status = true;
	} else {
		context.status = false;
		context.statusText = xhr.statusText;
	}
	if(context.callback)
		context.callback(context,context.userParams);
};

SocialtextAdaptor.prototype.close = function()
{
	return true;
};

config.adaptors[SocialtextAdaptor.serverType] = SocialtextAdaptor;
} //# end of 'install only once'
//}}}
/***
SocialtextStyleOverrides
***/

/*{{{*/
.headerShadow {padding: 2em 0em .5em 1em;}
.headerForeground {padding: 2em 0em .5em 1em;}

#st-page-wiki-title {
	font-size: 80%;
}
.subtitle {
	font-style: italic;
	font-size 80%;
}

/* from #st-tags */
.tagged {
	border-color: #bbeebb;
	background-color: #f4fff4;
}

.tagged .listTitle {
	color: #595;
	font-weight: bold;
}

.tagged .button {
	color: #000;
}

.selected .tagged {
	background-color: ColorPalette::TertiaryLight;
	border: 1px solid ColorPalette::TertiaryMid;
}

/* from #st-incoming-links */
.tagging {
	border-color: #ebb;
	background-color: #fff4f4;
}

.tagging .listTitle {
	color: #b78;
	font-weight: bold;
}

.tagging .button {
	color: #999;
}

.selected .tagging {
	background-color: ColorPalette::TertiaryLight;
	border: 1px solid ColorPalette::TertiaryMid;
}

.tiddler {/* Tiddler body */
	border:1px solid #ccc;
	margin:0.5em;
	background:#fff;
	padding:0.5em;
}

.viewer blockquote {border-left: 0px solid}

.tiddlyLinkNonExisting {
	font-style: italic;
	border-bottom: 1px dashed;
}

.editor input, .editor textarea {
	background: #ffd;
	border-style: solid;
	border-color: #888 #ccc #ccc #888;
	border-width: 2px;
}

.tabContents {white-space: nowrap;}

#displayArea {margin: 1em 20em 0em 14em;}

#sidebar {
	position: absolute;
	right: 3px;
	width: 21em;
	font-size: .9em;
}

#sidebarOptions .button {
	border-color: #eee;
}

#sidebarTabs .tabContents {
	width: 20em;
	overflow: hidden;
}

.viewer tt {
	font-size: 1.2em;
	line-height: 1.4em;
}

ul {list-style-type: square;}
ul ul {list-style-type: circle;}

ol {list-style-type: decimal;}
ol ol {list-style-type: decimal;}
ol ol ol {list-style-type: decimal;}
ol ol ol ol {list-style-type: decimal;}
ol ol ol ol ol {list-style-type: decimal;}
ol ol ol ol ol ol {list-style-type: decimal;}

/*}}}*/
/***
SocialtextScreenStyle
http://www.eu.socialtext.net/static/2.0.0.1/css/st/screen.css
***/

/*{{{*/
body {
	font-family: Arial, sans-serif;
	color: #000;
	background: #eee;
	margin: 0;
}

/* Wiki Navigation */

.st-wiki-nav {
	clear: both;
	margin-left: 10px;
	margin-right: 10px;
}
.st-wiki-nav-content {
	background: url('../../images/st/wiki-nav/solid.gif') repeat-x left bottom;
	margin-left: 24px;
	margin-right: 24px;
	padding-top: 3px;
	min-height: 24px;
}
* html .st-wiki-nav-content {
	padding-bottom: 3px;
	height: 24px;
}

.st-wiki-nav-right {
	background: url('../../images/st/wiki-nav/right-round.gif') no-repeat bottom right;
}

.st-wiki-nav-left {
	background: url('../../images/st/wiki-nav/left-round.gif') no-repeat bottom left;
}

#st-home {
	float: left;
	margin-right: 60px;
	padding-top: 2px;
}

#st-home-link {
	color: white;
	text-decoration: none;
	font-weight: bold;
	font-family: Helvetica, sans-serif;
	font-size: 90%;
}

#st-editing-prefix-container {
	border-collapse: collapse;
	width: 100%;
	padding: 0px;
	margin: 0px;
	margin-bottom: -20px;
}

#st-editing-prefix-container tr td {
	margin: 0px;
	padding: 0px;
}

#st-editing-title {
	color: black;
	background-color: white;
	text-decoration: none;
	font-weight: bold;
	font-family: Helvetica, sans-serif;
	font-size: 90%;
	margin-bottom: 0.4em;
}

#st-wiki-title-invite {
	font-size: 50%;
	font-family: Helvetica, sans-serif;
}

#st-wiki-title-central-page-link {
	font-size: 50%;
	font-family: Helvetica, sans-serif;
}

#st-wiki-title-invite a {
	color: #00f;
}

#st-wiki-logo {
	text-align: center;
	clear: both;
}

#st-wiki-logo-image {
}

.st-wiki-nav-actions {
	float: right;
	color: black;
	font-size: 75%;
	padding-top: 3px;
}

.st-wiki-nav-actions a {
	padding: 2px;
	color: white;
	text-decoration: none;
	font-family: Helvetica, sans-serif;
}

/* Wiki Subnav */

#st-wiki-subnav {
	margin-top: 2px;
	font-size: 70%;
	font-weight: bold;
	font-family: Helvetica, sans-serif;
	color: #888;
}

#st-wiki-subnav a {
	padding: 2px;
	color: #008;
	text-decoration: none;
}

#st-wiki-subnav-right {
	float: right;
	margin-right: 6em;
}

#st-wiki-subnav-left {
	float: left;
	margin-left: 6em;
}
* html #st-wiki-subnav-left {
	margin-left: 3em;
}

/* Wiki Navigation Search Bar */

#st-search-form {
	margin: 0;
	padding: 0;
	padding-top: 1px;
}

#st-search-form .button-table {
	float: left;
	font-size: 79%;
	font-weight: bold;
	margin-left: 5px;
	margin-top: 1px;
}

#st-search-form #st-search-term {
	float: left;
	font-size: 60%;
}

/* Content Outline */

#st-content-border, #st-edit-border {
	position: relative;
	clear: both;
	margin-left: 3px;
	margin-right: 2px;
	margin-bottom: 0px;
	margin-top: 0px;
	border-bottom: 1px solid #eee;
}

#st-content-border-left, #st-edit-border-left {
	background: url('../../images/st/page-shadow/left.gif') left top repeat-y;
	position: relative;
}

#st-content-border-right, #st-edit-border-right {
	background: url('../../images/st/page-shadow/right.gif') right top repeat-y;
	position: relative;
}

#st-content-border-top, #st-edit-border-top {
	position: relative;
	background: url('../../images/st/page-shadow/top.gif') left top repeat-x;
}

#st-content-border-bottom, #st-edit-border-bottom {
	background: url('../../images/st/page-shadow/bottom.gif') left bottom repeat-x;
	position: relative;
}

#st-content-border-left-top, #st-edit-border-left-top {
	background: url('../../images/st/page-shadow/left-top.gif') left top no-repeat;
	position: relative;
}
#st-content-border-right-top, #st-edit-border-right-top {
	background: url('../../images/st/page-shadow/right-top.gif') right top no-repeat;
	position: relative;
}

#st-content-border-left-bottom, #st-edit-border-left-bottom {
	background: url('../../images/st/page-shadow/left-bottom.gif') left bottom no-repeat;
	position: relative;
}

#st-content-border-right-bottom, #st-edit-border-right-bottom {
	background: url('../../images/st/page-shadow/right-bottom.gif') right bottom no-repeat;
	padding-top: 5px;
	padding-bottom: 9px;
	position: relative;
}

* html #st-content-border-right-bottom, * html #st-edit-border-right-bottom {
	padding-top: 4px;
	padding-left: 7px;
	padding-right: 8px;
	position: relative;
}

.st-content-width-controller {
	width: 100%;
	position: relative;
	border-collapse: collapse;
}
.st-content-width-controller td {
	vertical-align: top;
}
.st-content {
	position: relative;
	background-color: white;
	margin-top: 0px;
	margin-left: 7px;
	margin-right: 8px;
	margin-bottom: -1px;
	border-left: 1px dotted #80a9f3;
	border-right: 1px dotted #80a9f3;
	border: 1px solid #80a9f3;
	padding: 6px 12px 12px 12px;
}
* html .st-content {
	margin-top: 0px;
	margin-left: 0px;
	margin-right: 0px;
}

/* This textarea is only for Safari. However, if we use display:none; here Safari ignores the .value operation in JS */
#st-raw-wikitext-textarea {
	width:1px;
	height:1px;
	margin:0;
	padding:0;
}

/* Action Buttons */
.button-table, .button-table tr td {
	border-collapse: collapse;
	margin: 0;
	padding: 0;
}
.button-rounded {
	background: url('../../images/st/grey-button/left-top-rounded.png') top left no-repeat;
	margin: 0;
}
.button-rounded-right-top {
	background: url('../../images/st/grey-button/right-top-rounded.png') top right no-repeat;
	margin: 0;
}
.button-rounded-left-bottom {
	background: url('../../images/st/grey-button/left-bottom-rounded.png') bottom left no-repeat;
	margin: 0;
}
.button-rounded-right-bottom {
	background: url('../../images/st/grey-button/right-bottom-rounded.png') bottom right no-repeat;
	margin: 0;
}
.button-straight {
	background: url('../../images/st/grey-button/left-top-straight.png') top left no-repeat;
	margin: 0;
}
.button-straight-right-top {
	background: url('../../images/st/grey-button/right-top-straight.png') top right no-repeat;
	margin: 0;
}
.button-straight-left-bottom {
	background: url('../../images/st/grey-button/left-bottom-straight.png') bottom left no-repeat;
	margin: 0;
}
.button-straight-right-bottom {
	background: url('../../images/st/grey-button/right-bottom-straight.png') bottom right no-repeat;
	margin: 0;
}
.button-content {
	font-size: 90%;
}
.button-content a {
	display: block;
	padding: 2px;
	padding-left: 10px;
	padding-right: 10px;
	font-family: Helvetica, Verdana, sans-serif;
	font-weight: bold;
	text-decoration: none;
	color: black;
}

.button-content input.submit {
	border: 0px;
	padding: 2px;
	padding-left: 10px;
	padding-right: 10px;
	font-family: Helvetica, Verdana, sans-serif;
	font-weight: bold;
	text-decoration: none;
	color: black;
	background-color: transparent;
}

/* Personal Homepage */

#st-homepage {
	background: white url('../../images/st/homepage/blue-fade.gif') top left no-repeat;
}

#st-homepage-layout {
	margin-top: 15px;
	clear: both;
	width: 100%;
	border-collapse: collapse;
}

#st-homepage-layout tr td.st-homepage-layout-cell {
	padding: 5px;
	vertical-align: top;
}

#st-homepage-layout-dashboard {
	width: 50%
}

#st-homepage-layout-notes {
	width: 50%;
}

#st-homepage-notes, #st-homepage-dashboard {
	text-align: left;
	width: 95%;
}

#st-user-greeting, #st-wiki-title {
	font-family: Helvetica, Verdana, sans-serif;
	font-size: 150%;
}
#st-wiki-title {
	margin-left: 5px;
}

#st-user-greeting {
	position: relative;
	text-align: right;
	float: right;
}

#st-group-notes-content, #st-personal-notes-content {
}

.st-homepage-section {
	margin-bottom: 15px;
}

#st-homepage-notes .st-homepage-section {
	background-color: white;
	border: 1px solid #aaa;
	padding: 15px;
}

.st-homepage-section-title {
	font-size: 110%;
	font-family: Helvetica, Verdana, sans-serif;
}

#st-homepage-notes .st-homepage-section-title {
	color: #aaa;
	text-decoration: underline;
}

.st-homepage-notes-edit-link {
	background: url('../../images/st/homepage/edit-icon.gif') no-repeat left top;
	display: block;
	text-indent: -2000px;
	height: 13px;
	width: 36px;
	text-decoration: none;
	padding:0;
}
* html .st-homepage-notes-edit-link {
	border:1px solid white;
}

.st-homepage-notes-edit {
	font-family: Verdana, sans-serif;
	font-size: 65%;
	float: right;
}

.st-homepage-notes-content {
	font-size: 85%;
	margin-top: 10px;
	padding-top: 0px;
	padding-bottom: 0px;
	font-family: Verdana, Helvetica, sans-serif;
}

#st-dyk {
	border-color: #cca !important;
	background-color: #ffe !important;
}

#st-dyk-title {
	color: #e4a020 !important;
	text-decoration: none !important;
}


/* Homepage Simple List */

#st-whats-new-title-link {
	background: url('../../images/st/homepage/icon-28-pages.gif') no-repeat left top;
}
#st-watchlist-title-link {
	background: url('../../images/st/homepage/icon-28-star.gif') no-repeat left top;
}
#st-wikis-title-link {
	background: url('../../images/st/homepage/icon-28-group.gif') no-repeat left top;
}
.st-homepage-simplelist-title-link {
	display: block;
	padding-left: 32px;
	min-height: 32px;
}
* html .st-homepage-simplelist-title-link {
	height: 32px;
}

.st-homepage-simplelist-title {
}

.st-homepage-simplelist-table {
	margin-left: 25px;
	border: 1px dashed #ddd;
	border-collapse: collapse;
	font-family: Verdana, Helvetica, sans-serif;
	font-size: 80%;
	width: 95%;
}

.st-homepage-simplelist-table td {
	padding: 2px;
}

.st-homepage-simplelist-table tr.st-homepage-simplelist-row-odd {
	background-color: #f3f7f7;
}

.st-homepage-simplelist-table tr.st-homepage-simplelist-row-even {
	background-color: white;
}

.st-homepage-simplelist-table a {
	color: #4f55dd;
	text-decoration: none;
}

.st-homepage-simplelist-table a:visited {
	color: #551a8b;
}

.st-homepage-simplelist-subleft {
	font-size: 80%;
	margin-left: 1em;
	color: #666;
}

.st-homepage-simplelist-right {
	width: 20%;
}

.st-homepage-simplelist-subright {
	font-size: 80%;
	color: #666;
}

.st-homepage-simplelist {
}

.st-homepage-simplelist-header {
	min-height: 35px;
}

.st-homepage-simplelist-header .button-table {
	float: right;
	margin-right: 15px;
	font-size: 95%;
}

.st-homepage-simplelist-header .button-table .button-content {
	padding: 1px;
}

.st-homepage-whatsnew-author, .st-homepage-whatsnew-date {
	color: #555;
}
.st-homepage-whatsnew-attribution {
	padding-left: 1em;
	font-size: 80%;
	color: #aaa;
}

/* Homepage Wikis List */

#st-wikis-title {
}

/* Data and Templates */

.st-jst-template, .st-json {
	display: none;
}

/* Page Sidebox Common Styles */

#st-page-boxes-toggle {
	position: relative;
	float: right;
	text-align: right;
	font-family: Verdana, Arial, sans-serif;
	font-weight: bold;
	font-size: 80%;
	margin-bottom: 0.7em;
}

#st-page-boxes-toggle-link {
	text-decoration: none;
}

#st-page-boxes-underlay {
	float: right;
	margin-top: -10px;
	margin-right: 10px;
	background: white;
	z-index: 198;
	clear: both;
	margin-left: 15px;
}
* html #st-page-boxes-underlay {
	margin-right: 4px;
}
#st-page-boxes {
	background: inherit;
	position: absolute;
	right: 23px;
	z-index: 199;
	margin-top: 15px;
	margin-left: 20px;
}
#st-page-boxes, #st-page-boxes-underlay {
	width: 225px;
	/* padding-left: 15px; */ /* Gives the white border effect, cwest dislikes it. */
}

.st-page-box {
	border: 1px solid black;
	padding: 5px;
	font-family: Verdana, Helvetica, sans-serif;
	font-size: 80%;
	margin-top: 15px;
}

.st-page-box-title {
	font-family: Helvetica, Verdana, sans-serif;
	font-weight: bold;
	margin-bottom: 10px;
}

.st-page-box-listing {
	margin: 0;
	padding: 0;
}

.st-page-box-listing-entry {
	display: block;
}

.st-page-boxes-nobacklinks {
	font-family: Verdana, Helvetica, sans-serif;
	font-size: 90%;
	color: #888;
}

.st-page-box-first {
	margin-top: 0px;
}

/* Page Display */

#st-page-content {
	clear: left;
	margin-top: 6px;
	margin-bottom: 0;
	padding-bottom: 0;
}

#st-page-content, #st-page-content td {
	font-family: Verdana, Helvetica, sans-serif;
	font-size: 90%;
}

#st-page-wiki-title {
	font-family: Helvetica, Verdana, sans-serif;
	font-size: 65%;
	font-weight: bold;
	color: #aaa;
	margin-bottom: 0.2em;
	margin-top: 0.1em;
	padding-top: 0;
}

#wiki {
	margin: 0;
	padding: 0;
}

#st-page-title {
}

#st-page-titletext, .st-page-title {
	font-family: Helvetica, Verdana, sans-serif;
	font-size: 150%;
	font-weight: bold;
	color: #888;
	border-bottom: 1px solid #888;
}

#st-newpage-pagename-edit {
	font-family: inherit;
	font-size: inherit;
	font-weight: inherit;
	color: #000;
	border: 1px solid black;
	padding-left: 0.3em;
	background-color: #ffd;
}

#st-page-details {
	font-style: italic;
	font-size: 75%;
	font-family: Georgia, serif;
	margin: 6px 10px 0 10px;
}

#st-page-details-feed-icon {
	vertical-align: middle;
	border: none;
}

#st-page-stats {
	float: right;
	vertical-align: middle;
}

#st-attribution {
	float: left;
	margin-bottom: 10px;
}

#st-page-editing-wysiwyg {
	background: #ffd;
	border-style: solid;
	border-color: #888 #ccc #ccc #888;
	border-width: 2px;
	width: 100%;
}

#st-page-editing-toolbar {
	margin-left: -6px;
	overflow: hidden;
	float: left;
	height: 25px;
}

#wikiwyg_wikitext_textarea {
	margin-top: 4px;
	background: #ffd;
	border-style: solid;
	border-color: #888 #ccc #ccc #888;
	border-width: 2px;
	width: 100%;
	font-family: monospace;
}

#st-page-maincontent {
}

#st-page-editing, #wikiwyg_wikitext_textarea {
}

#st-page-editing-pagebody-decoy, #st-page-editing-wysiwyg {
	display: none;
}

#st-editing-tools-edit {
	display: none;
}

#st-mode-wysiwyg-button
{
	font-size: 70%;
	margin-left: 4em;
}

#st-mode-wikitext-button
{
	font-size: 70%;
}

#st-edit-tips
{
	font-size: 70%;
}

.wikiwyg_button {
	background: #FFFFFF;
	border: 1px solid #FFFFFF;
	cursor: pointer;
	width: 20px;
	height: 20px;
	vertical-align: bottom;
}

.wikiwyg_button:hover {
	border: 1px outset;
}

.wikiwyg_button:active {
	border: 1px inset;
}

#wikiwyg_toolbar {
	display: none;
}

/* Sidebox Pagetools: Revisions, Watchlist */
#st-side-box-pagetools {
	border-collapse: collapse;
}

#st-rewind-norevisions {
	font-family: Helvetica, Arial, sans-serif;
	font-size: 11px;
	color: #777;
	text-decoration: none;
}

#st-side-box-pagetools a {
	font-family: Helvetica, Arial, sans-serif;
	font-size: 11px;
	color: #555;
	text-decoration: none;
}

/* Page View Tags/Incoming Links Sidebox */

#st-tags {
	background: #f4fff4;
	border-color: #bbeebb;
	color: #999;
}

#st-tags-title {
	color: #595;
}

#st-tags-addlink, #st-tags-addbutton {
	font-weight: bold;
}

#st-tags-listing {
	margin-bottom: 5px;
}

#st-tags-addinput, #st-tags-message, #st-tags-suggestion {
	display: none;
}

#st-tags-deletemessage {
	font-size: 90%;
	color: #555;
	display: none;
	margin-top: 0.5em;
	margin-bottom: 0.5em;
}

#st-tags-suggestion {
	margin-top: 2px;
}

.st-tags-level1 {
	font-size: 90%;
}

.st-tags-level2 {
	font-size: 100%;
}

.st-tags-level3 {
	font-size: 110%;
}

.st-tags-level4 {
	font-size: 120%;
}

.st-tags-level5 {
	font-size: 130%;
}

.st-tags-tagline .st-tags-tagdelete {
	text-decoration: none;
	color: #ccc;
}

.st-tags-tagline a {
	text-decoration: none;
	color: #444;
}

#st-tags-field {
	width: 95%;
}

#st-incoming-links {
	border-color: #ebb;
	background-color: #fff4f4;
}

#st-incoming-links-title {
	color: #b78;
}

#st-attachments {
	border-color: #bbe;
	background-color: #f4f4ff;
}

#st-attachments-uploadbutton, #st-attachments-managebutton {

}
#st-attachments-buttons-uploadbutton {
	margin: 0px;
	padding: 0px;
	padding-left: 2px;
}
#st-attachments-buttons-managebutton {
	margin: 0px;
	padding: 0px;
	padding-right: 2px;
}

#st-attachments-buttons td {
	padding-right: 3px;
	font-size: 99%;
}

#st-attachments-buttons {
	border-collapse: collapse;
	margin: 0px;
	padding: 0px;
	margin-top: 5px;
}

#st-attachments-title {
	color: #77b;
}

.st-attachments-line {
	width:100%;
	overflow:hidden;
}

/* Actions Bar */

#st-actions-bar-spacer {
	clear:both;
	height:0.5em;
	overflow:hidden;
}

#st-actions-bar-spacer-clear {
	clear:both;
	height:1px;
	overflow:hidden;
}


#st-actions-bar, #st-editing-tools-bar {
	margin-left: 30px !important;
	margin-right: 30px !important;
}

/* Footer */
#st-footer {
	margin-top: -8px;
	margin-bottom: 5px;
	clear: both;
}

/* Socialtext Attribution */

#st-socialtext-attribution {
	clear: both;
	text-align: center;
	font-size: 80%;
	font-family: Helvetica, sans-serif;
}

#st-socialtext-attribution-link {
	text-decoration: none;
}

#st-socialtext-attribution-image {
	border: 0;
}


/* Page Actions */

#st-edit-button-border-left-middle, #st-login-to-edit-button-border-left-middle {
	background: url('../../images/st/button-blue/left-middle.gif') left top repeat-y;
}
#st-edit-button-border-right-middle, #st-login-to-edit-button-border-right-middle {
	background: url('../../images/st/button-blue/right-middle.gif') right top repeat-y;
}

#st-edit-button-border-left-top, #st-login-to-edit-button-border-left-top {
	background: url('../../images/st/button-blue/left-top.gif') left top no-repeat;
}
#st-edit-button-border-right-top, #st-login-to-edit-button-border-right-top {
	background: url('../../images/st/button-blue/right-top.gif') right top no-repeat;
}

#st-edit-button-border-left-bottom, #st-login-to-edit-button-border-left-bottom {
	background: url('../../images/st/button-blue/left-bottom.gif') left bottom no-repeat;
}

#st-edit-button-border-right-bottom, #st-login-to-edit-button-border-right-bottom {
	background: url('../../images/st/button-blue/right-bottom.gif') right bottom no-repeat;
}

#st-edit-button-link, #st-login-to-edit-button-link {
}

#st-comment-button-border-left-middle {
	background: url('../../images/st/button-purple/left-middle.gif') left top repeat-y;
}

#st-comment-button-border-right-middle {
	background: url('../../images/st/button-purple/right-middle.gif') right top repeat-y;
}

#st-comment-button-border-left-top {
	background: url('../../images/st/button-purple/left-top.gif') left top no-repeat;
}

#st-comment-button-border-right-top {
	background: url('../../images/st/button-purple/right-top.gif') right top no-repeat;
}

#st-comment-button-border-left-bottom {
	background: url('../../images/st/button-purple/left-bottom.gif') left bottom no-repeat;
}

#st-comment-button-border-right-bottom {
	background: url('../../images/st/button-purple/right-bottom.gif') right bottom no-repeat;
}

#st-comment-button-link {
}

#st-save-button-border-left-middle {
	background: url('../../images/st/button-green/left-middle.gif') left top repeat-y;
}
#st-save-button-border-right-middle {
	background: url('../../images/st/button-green/right-middle.gif') right top repeat-y;
}

#st-save-button-border-left-top {
	background: url('../../images/st/button-green/left-top.gif') left top no-repeat;
}
#st-save-button-border-right-top {
	background: url('../../images/st/button-green/right-top.gif') right top no-repeat;
}

#st-save-button-border-left-bottom {
	background: url('../../images/st/button-green/left-bottom.gif') left bottom no-repeat;
}

#st-save-button-border-right-bottom {
	background: url('../../images/st/button-green/right-bottom.gif') right bottom no-repeat;
}

#st-save-button-link {
}

#st-preview-button-border-left-middle {
	background: url('../../images/st/button-gold/left-middle.gif') left top repeat-y;
}
#st-preview-button-border-right-middle {
	background: url('../../images/st/button-gold/right-middle.gif') right top repeat-y;
}

#st-preview-button-border-left-top {
	background: url('../../images/st/button-gold/left-top.gif') left top no-repeat;
}
#st-preview-button-border-right-top {
	background: url('../../images/st/button-gold/right-top.gif') right top no-repeat;
}

#st-preview-button-border-left-bottom {
	background: url('../../images/st/button-gold/left-bottom.gif') left bottom no-repeat;
}

#st-preview-button-border-right-bottom {
	background: url('../../images/st/button-gold/right-bottom.gif') right bottom no-repeat;
}

#st-preview-button-link {
}

#st-cancel-button-border-left-middle {
	background: url('../../images/st/button-crimson/left-middle.gif') left top repeat-y;
}
#st-cancel-button-border-right-middle {
	background: url('../../images/st/button-crimson/right-middle.gif') right top repeat-y;
}

#st-cancel-button-border-left-top {
	background: url('../../images/st/button-crimson/left-top.gif') left top no-repeat;
}
#st-cancel-button-border-right-top {
	background: url('../../images/st/button-crimson/right-top.gif') right top no-repeat;
}

#st-cancel-button-border-left-bottom {
	background: url('../../images/st/button-crimson/left-bottom.gif') left bottom no-repeat;
}

#st-cancel-button-border-right-bottom {
	background: url('../../images/st/button-crimson/right-bottom.gif') right bottom no-repeat;
}

#st-cancel-button-link {
}

#st-edit-more-button-border-left-middle {
	background: url('../../images/st/button-blue/left-middle.gif') left top repeat-y;
}
#st-edit-more-button-border-right-middle {
	background: url('../../images/st/button-blue/right-middle.gif') right top repeat-y;
}

#st-edit-more-button-border-left-top {
	background: url('../../images/st/button-blue/left-top.gif') left top no-repeat;
}
#st-edit-more-button-border-right-top {
	background: url('../../images/st/button-blue/right-top.gif') right top no-repeat;
}

#st-edit-more-button-border-left-bottom {
	background: url('../../images/st/button-blue/left-bottom.gif') left bottom no-repeat;
}

#st-edit-more-button-border-right-bottom {
	background: url('../../images/st/button-blue/right-bottom.gif') right bottom no-repeat;
}

#st-edit-more-button-link {
}

.st-page-action-button-link {
	min-height: 24px;
	min-width: 100px;
	text-align: center;
	font-family: Helvetica, Verdana, sans-serif;
	font-size: 90%;
	text-decoration: none;
	color: #fff;
	font-weight: bold;
	display: block;
	padding-top: 8px;
	padding-bottom: 0px;
	margin-bottom: -3px;
	width: 100%;
	margin-left: -2px;
}
* html .st-page-action-button-link {
	padding-top: 5px;
	padding-bottom: 0px;
	height: 24px;
}

.st-page-action-button {
	float: left;
	margin: 0;
	padding: 0;
	margin-right: 10px;
	min-height: 20px;
	border-collapse: collapse;
	width: 100px;
}

/* Attach File Interface */

#st-attachments-attachinterface {
	font-family: Helvetica, sans-serif;
	font-size: 90%;
	display: none;
	position: fixed;
	left: 0px;
	top: 0px;
	width: 100%;
	height: 100%;
	z-index: 2000;
	background-image: url('../../images/st/popup/bg.png');
}
#st-attachments-manageinterface {
	font-family: Helvetica, sans-serif;
	font-size: 90%;
	display: none;
	position: absolute;
	left: 0px;
	top: 0px;
	width: 100%;
	height: 100%;
	z-index: 2000;
	background-image: url('../../images/st/popup/bg.png');
}

* html #st-attachments-attachinterface {
	background-image: none;
}
* html #st-attachments-manageinterface {
	background-image: none;
}
* html .popup-overlay {
	background-image: url('../../images/st/popup/bg.png');
	background-color: #000;
	opacity: .70;
	position: absolute;
	left: 0px;
	top: 0px;
	width: 100%;
	height: 100%;
	z-index: 2001;
}

#st-attachments-attach-interface {
	z-index: 2002;
	background-color: #fff;
	color: #000;
	border: 4px solid #ccc;
	padding: 1em;
	width: 520px;
	margin-left: auto;
	margin-right: auto;
	margin-top: 10%;
	position: absolute;
	top: 0px;
}

* html #st-attachments-attach-interface {
}

#st-attachments-attach-formtarget {
	width: 0px;
	height: 0px;
	border: 0;
	padding: 0;
	margin: 0;
}

#st-attachments-attach-message {
	font-size: 90%;
	font-family: Verdana, Arial, Helvetica, Sans-Serif;
}

#st-attachments-attach-title {
	font-weight: bold;
	font-size: 120%;
}

#st-attachments-attach-close {
	float: right;
	margin-top: 6px;
}

#st-attachments-attach-uploadbutton {
	float: right;
	margin-right: 6px;
	margin-top: 6px;
	padding-bottom: 0;
}

#st-attachments-attach-fileprompt {
	margin: 0.2em 0 0.4em 0;
	padding-bottom: 0px;
}

#st-attachments-attach-submit {
	font-size: 90%;
	font-weight: bold;
}

#st-attachments-attach-filename {
	font-size: 90%;
}

#st-attachments-attach-uploadmessage {
	font-weight: bold;
	margin-bottom: 1em;
	display: none;
}

#st-attachments-attach-error {
	font-weight: bold;
	color: #f00;
	margin-bottom: 1em;
	display: none;
}

#st-attachments-attach-list {
	display: none;
	color: #666;
	font-size: 90%;
	margin-top: 1em;
	margin-bottom: 1em;
	border-top: 1px solid #4949BA;
	border-bottom: 1px solid #4949BA;
	background-color: #F5F5F5;
	padding: 3px;
}

.st-attachments-attach-listlabel {
	font-size: 90%;
	color: #4949BA;
}

/* Queue File Dialog */

#st-attachmentsqueue-interface {
	font-family: Helvetica, sans-serif;
	font-size: 90%;
	display: none;
	position: fixed;
	left: 0px;
	top: 0px;
	width: 100%;
	height: 100%;
	background-image: url('../../images/st/popup/bg.png'); /* Don't forget IE hack for ship! */
	z-index: 2000;
}

* html #st-attachmentsqueue-interface {
	background-image: none;
}

#st-attachmentsqueue-dialog {
	z-index: 2002;
	background-color: #fff;
	color: #000;
	border: 4px solid #ccc;
	padding: 1em;
	width: 530px;
	margin-left: auto;
	margin-right: auto;
	margin-top: 10%;
	position: absolute;
	top: 0px;
}

* html #st-attachmentsqueue-dialog {
}

#st-attachmentsqueue-fileprompt {
	margin-bottom: 0.4em;
	margin-top: 0;
	padding-bottom: 0;
}

#st-attachmentsqueue-title {
	font-weight: bold;
	font-size: 120%;
}

#st-attachmentsqueue-close {
	float: right;
	margin-top: 6px;
}

#st-attachmentsqueue-uploadbutton {
	float: right;
	margin-right: 6px;
	margin-top: 6px;
	padding-bottom: 0;
}

#st-attachmentsqueue-submit {
	font-size: 90%;
}

#st-attachmentsqueue-filename {
	font-size: 90%;
}

#st-attachmentsqueue-message {
	font-size: 90%;
	font-family: Verdana, Arial, Helvetica, Sans-Serif;
}

#st-attachmentsqueue-uploadmessage {
	font-weight: bold;
	margin-bottom: 1em;
	display: none;
}

#st-attachmentsqueue-error {
	font-weight: bold;
	color: #f00;
	margin-bottom: 1em;
	display: none;
}

#st-attachmentsqueue-list {
	display: none;
	color: #666;
	font-size: 90%;
	margin-top: 1em;
	margin-bottom: 1em;
	border-top: 1px solid #4949BA;
	border-bottom: 1px solid #4949BA;
	background-color: #F5F5F5;
	padding: 3px;
}

.st-attachmentsqueue-listlabel {
	font-size: 90%;
	color: #4949BA;
}

/* Lists */

tr.st-trbg-even, tr.st-trbg-even td{
	background-color: #f3f7f7;
}

tr.w-st-even-row, tr.w-st-even-row td {
	background-color: #f3f7f7;
}

.query-results-header-title, .query-results-header-last-edit-by {
	text-align: left;
}


.query-results-row-revisions {
	text-align: right;
}

.query-results-content {
	font-size: 85%;
	border-collapse: collapse;
	border: 1px dashed #ddd;
	border-left: 1px solid #ddd;
	border-right: 1px solid #ddd;
}

.query-results-row {
	border-collapse: collapse;
	border: 1px dashed #ddd;
	border-left: 1px solid #ddd;
	border-right: 1px solid #ddd;
}

.query-results-row a {
	text-decoration: underline;
	color: #00f;
}

.query-results-row td {
	font-family: Verdana;
	padding: 0.3em;
	border-left: 1px dashed #ddd;
	border-right: 1px dashed #ddd;
	border-top: 1px solid #ddd;
	border-bottom: 1px solid #ddd;
}

.query-results-header-row {
	border-collapse: collapse;
	border: 1px dashed #ddd;
	border-left: 1px solid #ddd;
	border-right: 1px solid #ddd;
}

.query-results-header-row a {
	text-decoration: underline;
	color: #00f;
}

.query-results-header-row th {
	font-family: Helvetica;
	padding: 0.3em;
	border-left: 1px dashed #ddd;
	border-right: 1px dashed #ddd;
	border-top: 1px solid #ddd;
	border-bottom: 1px solid #ddd;
}

div.st-actionbutton {
	float: left;
}

div#deleteme-st-actions-bar {
	clear: both;
	margin: 0.8em 20px 0.2em auto;
	padding: 0;
}

/* Manage File Interface */



#st-attachments-manage-interface {
	z-index: 2002;
	background-color: #fff;
	color: #000;
	border: 4px solid #ccc;
	padding: 1em;
	width: 520px;
	margin-left: auto;
	margin-right: auto;
	margin-top: 10%;
	position: absolute;
	top: 0px;
}

#st-attachments-manage-filetable {
	height: 150px;
	margin: 0;
	padding: 0;
	width: 100%;
	overflow: auto;
	border: 1px solid #ccc;
}

#st-attachments-manage-filelisting tbody td {
	font-size: 90%;
}
#st-attachments-manage-filelisting {
	width: 100%;
	border-collapse: collapse;
	border: 0;
	margin: 0;
	padding: 0;
}

#st-attachments-manage-fileheader {
	background: #ccc;
	font-weight: bold;
	border-bottom: 1px black solid;
}

#st-attachments-manage-close {
	float: right;
	margin-top: 3px;
	margin-right: -2px;
	font-weight: bold;
}

#st-attachments-manage-delete {
	margin-top: 3px;
	float: left;
	font-weight: bold;
}

.st-attachments-manage-filerow {
	border-bottom: 1px solid #ccc;
}

.row-odd {
	background-color: #eee;
}

.row-even {
	background-color: #fff;
}

.row-on {
	background-color: #009 !important;
	color: white !important;
}

.row-on a {
	color: #fff !important;
}

#st-attachments-manage-deletemessage {
	color: red;
}

/* Page tools icons */

#st-pagetools-print {
	background: url('../../images/st/pagetools/print.gif')
	left center no-repeat;
}

#st-pagetools-email {
	background: url('../../images/st/pagetools/email.gif')
	left center no-repeat;
}

#st-pagetools-tools {
	background: url('../../images/st/pagetools/tools.gif')
	left center no-repeat;
}

/*
 #st-pagetools-watch {
	background: url('../../images/st/pagetools/watch-blue.gif')
	left center no-repeat;
}
*/


/* *********** Settings *********** */

#st-settings-pane {
}
* html #settings-pane { font-size: 85%;}

.settings-start-table {
}
* html .settings-start-table { font-size: 90%;}

#st-settings-select {
	padding: 0px 10px 10px 10px;
	vertical-align: top;
	width: 1px;

	background-color: #eff1ec;
	border: none;
}

#st-settings-section {
	padding: 0px 10px 10px 10px;
	vertical-align: top;
}

.settings-top-header {
	margin-top: 1em;
	font-weight: bold;
	width: 15em;
}

.settings-header {
	margin-top: 1em;
	font-weight: bold;
}

.settings-selections {
	padding: 0px 0px 0px 20px;
	line-height: 1.5em;
}

.settings-selections a:visited, .settings-selections a:active {
	color: #0000ff;
}

.settings-link {
	clear: both;
	display: block;
}

.settings-section-left {
	text-align: right;
}

.settings-label {
	font-weight: bold;
}

.settings-help {
	color: #888;
}

.settings-comment {
}

.users-invite-message {
	padding: 0.5em 0.5em 0.5em 2em;
	background-color: #eee;
	/* This seems necessary to fix an IE bug that sometimes
		causes the text in this div to be invisible */
	z-index: 1000;
}

.workspace-entry-header {
	margin-top: .5em;
	font-weight: bold;
}

.workspace-entry {
	margin-left: 3em;
}

.workspace-entry-p {
	margin-top: .5em;
	margin-bottom: .75em;
}

.workspace-subentry {
	font-style: italic;
	font-weight: bold;
	margin-left: 1.5em;
}

.preferences-td {
	padding:.5em 0 1.5em 0;
}

.preferences-query {
	text-align: left;
}

.preference-radio {
	background-color: #cec;
}
.user-settings-listall-headings td {
	background-color: #eff3ef;
}

#st-settings-save {
	padding-bottom: 0.5em;
}

.standard-button-cancel {
	font-weight: bold;
	background-color: #71004b;

	border-left: 1px solid #aaa;
	border-top: 1px solid #aaa;
	border-bottom: 2px solid #333;
	border-right: 2px solid #333;
	color: #f4f3b9;
	width: 8em;
}

.standard-button-submit {
	font-weight: bold;
	background-color: #656084;

	border-left: 1px solid #aaa;
	border-top: 1px solid #aaa;
	border-bottom: 2px solid #333;
	border-right: 2px solid #333;
	color: #f4f3b9;
	width: 8em;
}

#st-settings {
	font-family: Verdana, Arial, Helvetica, Sans-Serif;
	font-size: 90%;
}


/* Listview Tabs */


#st-listview a:visited {
	color: #551a8b;
}
#st-listview-tabs ul {
	display: block;
	list-style: none outside;
	margin: 0 0 0 4em;
	padding: 0;
	font-family: Helvetica, Arial, Sans-serif;
	font-size: 80%;
}

#st-listview-tabs li {
	display: block;
	float: left;
	margin: 0 0.8em 0 0;
	padding: 3px 0.6em 0 0.6em;
	border: 1px solid #d8d8d8;
	border-bottom: 1px solid rgb(128, 169, 243);
	background-color: #f4f4f4;
	position: relative;
	bottom: -2px;
}

#st-listview-tabs li.spacer {
	margin: 0 0.8em 0 2em;
}

#st-listview-tabs a {
	color: #bbb;
	text-decoration: none;
}

#st-listview-tabs li.selected {
	background-color: #fff !important;
	border: 1px solid rgb(128, 169, 243) !important;
	border-bottom: 1px solid #fff !important;
	font-weight: bold !important;
}

#st-listview-tabs li.selected a {
	color: #000 !important;
}

/* Category List Display */

#st-category-display-links {
	margin-bottom: 1em;
	font-size: 90%;
}

#st-tag-listbody {
	font-family: Helvetica, Verdana, sans-serif;
}

/* Attachments List Display */

#st-attachments-list-body table.button-table {
	margin-top: 0.1em;
	font-size: 80%;
}


/* ********** PageTools Menu ************** */

div#st-editing-tools {
	float: left;
}

div#st-pagetools {
	z-index: 300;
	font-family: Helvetica, Verdana, sans-serif;
	font-size: 10px;
	float: right;
	margin: 18px 0 0 0em;
	color: #000;
	vertical-align: bottom;
	position: relative;
}

#st-pagetools a {
	text-decoration: none;
	color: black;
	padding-left: 17px;
}

#st-pagetools span {
	color: inherit;
	padding-left: 17px;
	vertical-align: top;
}

#st-pagetools span.st-watchlist-link {
	color: inherit;
	vertical-align: top;
}

.st-watchlist-link {
	cursor: pointer;
}

div#st-pagetools ul.level2 {
	z-index: 300;
	margin: 0;
	padding: 0;
	background: white;
	border: 1px solid #CCC;
	border-width: 0 1px;
}

div#st-pagetools li {
	position: relative;
	list-style: none;
	margin: 0;
	float: left;
	width: 7em;
	line-height: 11px;
}

div#st-pagetools ul ul li:hover {
	background: #BFE2FF;
}

div#st-pagetools li a {
	display: block;
	text-decoration: none;
}

div#st-pagetools>ul a {
	width: auto;
}

div#st-pagetools ul ul {
	position: absolute;
	width: auto;
	display: none;
}

div#st-pagetools ul ul li {
	line-height: 1.5em;
/*	width: 100%; */
	width: 14em;
}

.first {
	border-top: 1px solid #CCC;
}

.separator {
	border-bottom: 1px solid #CCC;
}

div#st-pagetools ul ul li a {
	border-bottom: 1px solid #CCC;
	padding-left: 15px;
	padding-right: 3px;
	margin-right: 3px;
	border: 0px;
}

div#st-pagetools li.submenu li.submenu:hover {
	z-index: 300;
	background-color: #BFE2FF;
}

div#st-pagetools ul.level1 li.submenu:hover ul.level2 {
	display:block;
}

div#st-pagetools ul.level2 {
	top: 1.0em;
	left: -9.5em;
}

/*

=head2 Revision List Display

Change these styles to update the page revision list.

*/

#st-revision-list-table {
	border-collapse: collapse;
	font-size: 85%;
	color: #000;
}

.st-page-title-decorator {
	color: #C80000;
}

.st-revision-header-emphasis {
	color: #C80000;
}

.st-revision-list-compare-button-row {
}

.st-revision-list-compare-button-cell {
	padding-top: 0.3em;
	text-align: center;
}

.st-revision-list-compare-button {
}

#st-revision-list-header-row {
}

#st-revision-list-header-select {
	padding: 6px 2px 2px 2px;
	text-align: center;
}

#st-revision-list-header-revision {
	padding: 6px 2px 2px 2px;
	text-align: left;
}

#st-revision-list-header-edited-by {
	padding: 6px 2px 2px 2px;
	text-align: center;
}

#st-revision-list-header-date {
	padding: 6px 2px 2px 2px;
	text-align: center;
}

.st-revision-list-row {
	border-collapse: collapse;
	border: 1px dashed #ddd;
	border-left: 1px solid #ddd;
	border-right: 1px solid #ddd;
}

.st-revision-list-row td {
	font-family: Verdana;
	padding: 0.3em;
	border-left: 1px dashed #ddd;
	border-right: 1px dashed #ddd;
	border-top: 1px solid #ddd;
	border-bottom: 1px solid #ddd;
}

.st-revision-list-row-select {
	padding: 3px 0 2px 0;
	text-align: center;
}

.st-revision-list-row-select-old {
}

.st-revision-list-row-select-new {
}

.st-revision-list-row-revision {
}

.st-revision-list-row-revision-link {
}

.st-revision-list-row-edited-by {
}

.st-revision-list-row-date {
}

/* Revision Menu */

#st-pagetools.st-revision-view-bar {
	float: left;
}

ul.st-revision-menu {
	list-style: none;
	margin: 0;
	padding: 0.2em;
	font-size: 80%;
}

ul.st-revision-menu li {
	float: left;
	padding: 0 0.4em 0 0.4em;
	border-right: thin solid #000000;
}

ul.st-revision-menu li.st-last {
	border-right: none;
}

#st-restore-revision-button {
	font-size: 80%;
}

/*

=head2 Revision Compare Display

When comparing two revisions of a page, these styles apply.

*/

#st-revision-compare-table {
	background-color: #f0f0f0;
}

#st-revision-compare-table td {
	background-color: white;
}

.st-revision-compare-old {
	background-color: #fdd;
	text-decoration: line-through;
}
.st-revision-compare-new {
	background-color: #dfd;
	font-weight: bold;
}

/* Weblog View */

#st-weblog {
	padding: 0;
}

#st-content-weblog-display-width-controller {
}
#st-content-weblog-display-width-controller-nav {
	width: 230px;
	margin-left: 15px;
	border-left: 5px solid #ddd;
	margin-top: -1px;
}

#st-weblog-content {
	font-family: Verdana, Helvetica, sans-serif;
	margin-top: -1px;
	margin-bottom: -1px;
	border-top: 1px solid #80a9f3;
	border-bottom: 1px solid #80a9f3;
}

#st-weblog-title {
	font-family: 'Trebuchet MS', Verdana, Helvetica, sans-serif;
	font-family: 'Times New Roman', serif;
	background-color: #80a9f3;
	color: #fff;
	font-size: 150%;
	font-weight: bold;
	padding: 0.2em;
	padding-left: 1em;
}

#st-weblog-wikititle {
	font-family: Helvetica, Verdana, sans-serif;
	font-style: italic;
	font-size: 40%;
	color: #fff;
	margin-bottom: 0.2em;
	margin-top: 0.1em;
	padding-top: 0;
}

#st-weblog-titletext {
	font-family: Helvetica, Verdana, sans-serif;
	font-weight: bold;
	color: #fff;
}

div.st-weblog-entry {
	margin-top: 0.2em;
	margin-bottom: 4.8em;
	padding: 0 1.5em 0 1.5em;
}

.st-page-title {
	clear: both;
}

div.st-weblog-entrytitle span.text {
	font-family: Helvetica, Verdana, sans-serif;
	font-size: 150%;
	font-weight: bold;
	color: #000;
}

.st-weblog-entrycontent {
	font-family: Verdana, Helvetica, sans-serif;
	font-size: 90%;
	border-bottom: 1px solid #888;
}

.st-weblog-byline {
	float: left;
	text-align: left;
	font-style: italic;
	font-size: 70%;
	font-family: Verdana, Helvetica, sans-serif;
}

.st-weblog-post-links {
	float: right;
	text-align: right;
	font-size: 70%;
	font-family: Verdana, Helvetica, sans-serif;
}

#st-weblog-archives, #st-weblog-navigation {
	position: relative;
	float: right;
	width: 230px;
}

#st-weblog-archives {
	margin-top: 15px;
	clear: right;
}

#st-weblog-archives-title, #st-weblog-navigation-title {
	margin-left: 15px;
	font-family: Helvetica, sans-serif;
	font-size: 95%;
	font-weight: bold;
	color: #999;
	border-bottom: 2px solid #f99;
	padding-bottom: 5px;
	padding-top: 5px;
	margin-bottom: 5px;
}

#st-weblog-navigation-content {
	margin-left: 15px;
	font-size: 80%;
}

#st-weblog-archives ul {
	margin: 0;
	padding: 0;
}

#st-weblog-archives ul li {
	/* list-type: none; */
	display: block;
	font-size: 80%;
	font-family: Helvetica, sans-serif;
	padding-left: 15px;
}

#st-weblog-newpost {
	padding: 0.5em 0.7em 0.3em 0.3em;
}

#st-weblog-newpost-button {
}

#st-weblog-actionbar-chooseweblog {
	float: right;
}

#st-weblog-postbyemail {
	font-size: 70%;
	font-family: Verdana, Helvetica, sans-serif;
	color: #def;
	padding-top: 0.4em;
}

#st-weblog-postbyemail-link {
	color: #00c;
}

.st-weblog-chooseprompt {
	font-size: 90%;
	font-family: Verdana, Helvetica, sans-serif;
	padding-right: 0.2em;
	color: #000;
}

.st-spacer {
	padding-right: 0.1em;
	padding-left: 0.1em;
}

.st-weblog-preventries {
	padding-bottom: 20px;
	clear: both;
}
.st-weblog-nextentries {
	clear: both;
}

div.st-weblog-entrynav {
	margin-top: 0.2em;
	margin-bottom: 1.8em;
	padding: 0;
}

span.st-weblog-previousentries, span.st-weblog-nextentries {
	font-size: 90%;
	font-family: Verdana, Helvetica, sans-serif;
	padding-left: 1em;
}

/* ******* Page Stats ******** */

#st-usagereport-navbar {
	font-size: 80%;
	padding: 0;
	margin: 0;
}

#st-usagereport-date {
	font-weight: bold;
	margin-top: 1em;
}

#st-page-usagereport h1 {
	font-size: 1.3em;
	font-weight: bold;
	margin-top: 1.2em;
	margin-bottom: 0.3em;
}

#st-page-usagereport h2 {
	font-size: 1.1em;
	font-weight: bold;
	margin-top: 0.8em;
	margin-bottom: 0.3em;
}

/* New Page */
#st-newpage-save, #st-newpage-duplicate {
	display: none;
	position: fixed;
	left: 0px;
	top: 0px;
	width: 100%;
	height: 100%;
	background: url('../../images/st/popup/bg.png'); /* Don't forget IE hack for ship! */
	z-index: 2000;
}

#st-newpage-save-interface {
	background-color: #fff;
	color: #000;
	border: 4px solid #ccc;
	padding: 0.5em;
	width: 450px;
	margin-left: auto;
	margin-right: auto;
	margin-top: 10%;
	position:absolute;
	top:0px;
	z-index:2003;
}

#st-newpage-duplicate-interface {
	background-color: #fff;
	color: #000;
	border: 4px solid #ccc;
	padding: 0.5em;
	width: 530px;
	margin-left: auto;
	margin-right: auto;
	margin-top: 10%;
	position:absolute;
	top:0px;
	z-index:2003;
}

#st-newpage-save-title, #st-newpage-duplicate-title {
	margin: 0;
	padding: 0;
	font-weight: bold;
	font-family: Helvetica, sans-serif;
	font-size: 100%;
}

#st-newpage-save-prompt, #st-newpage-duplicate-prompt {
	font-family: Helvetica, sans-serif;
	font-size: 90%;
	margin-bottom: 0.4em;
}

#st-newpage-save-buttons, #st-newpage-duplicate-buttons {
	margin-top: 0.8em;
	text-align: right;
}

.st-newpage-duplicate-option {
	font-family: Helvetica, sans-serif;
	font-size: 90%;
	margin: 0;
	padding: 0;
}

#st-newpage-duplicate-pagename {
	font-size: 90%;
}

.st-newpage-duplicate-emphasis {
	background-color: #FFFF00;
	font-weight: bold;
}

#st-newpage-save-field-pagename {
	margin-bottom: 0;
	margin-top: 0.2em;
	padding-bottom: 0;
	font-size: 90%;
}

#st-newpage-save-tip {
	margin-bottom: 0;
	margin-top: 1.2em;
	padding-bottom: 0;
	font-size: 75%;
	color: #888;
}

/* Wikitext Styling */

.wiki {
}

.wiki hr {
	margin-top: .4em;
	margin-bottom: .4em;
}

.wiki .short-rule {
	width: 25%;
}

.wiki .medium-rule {
	width: 50%
}

.wiki ul,
.wiki ol,
.wiki blockquote {
	margin-left: 2em;
	padding-left: 0em;
}

.wiki table {
	border-collapse: collapse;
}

.wiki td {
	border: 1px;
	border-style: solid;
	padding: .2em;
	vertical-align: top;
}

.wiki h1,
.wiki h2,
.wiki h3,
.wiki h4,
.wiki h5,
.wiki h6 {
	font-weight: bold;
	font-style: normal;
	margin-top: 0.1em;
	margin-bottom: 8px;
}

.wiki h1 {font-size: 200%;}
.wiki h2 {font-size: 170%;}
.wiki h3 {font-size: 145%;}
.wiki h4 {font-size: 125%;}
.wiki h5 {font-size: 110%;}
.wiki h6 {font-size: 100%;}

.wiki pre {
	background-color: #eee; /* XXX */
	margin-left: 1em;
	margin-right: 1em;
	padding: .2em;
}

.wiki .incipient {
	text-decoration: none;
	border-bottom: 1px dashed;
}

.wiki-include-title {
	background-color: #ccccff;
}

.wiki .wiki {
	position: relative;
	background-color: #ddddff;
	border: 1px solid #ccccff;
	padding: 3px;
}

.wafl_existence_error {
	color: rgb(200,0,0);
	border-bottom: 0.2em dashed rgb(200,0,0);
}

#st-edit-mode-container {
}

#st-edit-mode-view {
}

#st-page-editing-uploadbutton {
	z-index: 1500;
	float: left;
}

/* Comment UI */


body#st-commentui {
	background: #ffffff;
}

#st-commentui-container {
}

#st-commentui-container a:visited,
#st-commentui-container a:active {
	color: #00f;
}

#st-commentui-notetop {
}

#st-commentui-controls {
}

#st-commentui-savelink {
	background-color: #fffebd;
}

#st-commentui-cancellink {
}

#st-commentui-customfield {
}

#st-commentui-customfield .customfield-label {
}

#st-commentui-customfield .customfield-input {
}

#st-commentui-textarea {
	padding: 0;
	border-style: inset;
	border-width: thin;
	background-color: #ffd;
	color: black;
	width: 99%;
	height: 150px;
}

/*

=head2 Send Page by Email

Styles for the 'Send Page by Email' popup, accessed from the 'Email' dropdown
menu on the page bar.

*/

#email-page {
	background: #ffffff;
	font-size: 80%;
}

.email-page-row {
	clear: both;
}

.email-page-row-label {
	font-weight: bold;
	float: left;
	width: 5em;
	margin-left: 1.2em;
	margin-right: 1.2em;
	text-align: right;
}

.email-page-row-content {
	float: left;
	padding-bottom: 1.2em;
}

.email-page-user-select-column {
	float: left;
	padding-right: 1.2em;
	width: 14em;
}

#email-page-user-select-column-center {
	width: 10em;
}

.email-page-user-select-label {
	text-align: center;
}

#email-page-user-select-add-label {
	padding-top: 1em;
}

.email-page-user-select-button-group {
	padding-bottom: 2em;
}

.email-page-input {
	width: 120px;
	clear: both;
	display: block;
}


.email-page-select {
	width: 175px;
	font-size: x-small;
}

#email-page-error-message {
	text-align: center;
}

#email-page-buttons-container {
	clear: both;
}

#email-page-buttons {
	text-align: center;
}

.email-page-input-new {
	width: 175px;
}

/* System Status, Red with icon */

#st-system-status-alert {
	clear: both;
	width: 50%;
	margin-left: 25%;
	margin-top: 10px;
	padding: 5px;
	color: #c00;
	font-weight: bold;
	font-size: 80%;
	background: transparent url('../../images/st/system-message/important-note.gif') no-repeat 5px center;
	padding-left: 60px;
	min-height: 38px;
}
* html #st-system-status-alert {
	height: 38px;
}

/* System Status, Green */

#st-system-status {
	clear: both;
	text-align:center;
	width: 80%;
	margin-left: 10%;
	padding: 8px 0 3px 0;
	color: #0a0;
	font-family: Arial, Helvetica, sans-serif;
	font-size: 80%;
}

.socialtextLogo {
	text-align: center;
}
/*}}}*/
/***
|''Name:''|SparklinePlugin|
|''Description:''|Sparklines macro|
***/
//{{{
if(!version.extensions.SparklinePlugin) {
version.extensions.SparklinePlugin = {installed:true};

//--
//-- Sparklines
//--

config.macros.sparkline = {};
config.macros.sparkline.handler = function(place,macroName,params)
{
	var data = [];
	var min = 0;
	var max = 0;
	var v;
	for(var t=0; t<params.length; t++) {
		v = parseInt(params[t]);
		if(v < min)
			min = v;
		if(v > max)
			max = v;
		data.push(v);
	}
	if(data.length < 1)
		return;
	var box = createTiddlyElement(place,"span",null,"sparkline",String.fromCharCode(160));
	box.title = data.join(",");
	var w = box.offsetWidth;
	var h = box.offsetHeight;
	box.style.paddingRight = (data.length * 2 - w) + "px";
	box.style.position = "relative";
	for(var d=0; d<data.length; d++) {
		var tick = document.createElement("img");
		tick.border = 0;
		tick.className = "sparktick";
		tick.style.position = "absolute";
		tick.src = "data:image/gif,GIF89a%01%00%01%00%91%FF%00%FF%FF%FF%00%00%00%C0%C0%C0%00%00%00!%F9%04%01%00%00%02%00%2C%00%00%00%00%01%00%01%00%40%02%02T%01%00%3B";
		tick.style.left = d*2 + "px";
		tick.style.width = "2px";
		v = Math.floor(((data[d] - min)/(max-min)) * h);
		tick.style.top = (h-v) + "px";
		tick.style.height = v + "px";
		box.appendChild(tick);
	}
};


}
//}}}
/***
|''Name:''|CryptoFunctionsPlugin|
|''Description:''|Support for cryptographic functions|
***/
//{{{
if(!version.extensions.CryptoFunctionsPlugin) {
version.extensions.CryptoFunctionsPlugin = {installed:true};

//--
//-- Crypto functions and associated conversion routines
//--

// Crypto "namespace"
function Crypto() {}

// Convert a string to an array of big-endian 32-bit words
Crypto.strToBe32s = function(str)
{
	var be = Array();
	var len = Math.floor(str.length/4);
	var i, j;
	for(i=0, j=0; i<len; i++, j+=4) {
		be[i] = ((str.charCodeAt(j)&0xff) << 24)|((str.charCodeAt(j+1)&0xff) << 16)|((str.charCodeAt(j+2)&0xff) << 8)|(str.charCodeAt(j+3)&0xff);
	}
	while (j<str.length) {
		be[j>>2] |= (str.charCodeAt(j)&0xff)<<(24-(j*8)%32);
		j++;
	}
	return be;
};

// Convert an array of big-endian 32-bit words to a string
Crypto.be32sToStr = function(be)
{
	var str = "";
	for(var i=0;i<be.length*32;i+=8)
		str += String.fromCharCode((be[i>>5]>>>(24-i%32)) & 0xff);
	return str;
};

// Convert an array of big-endian 32-bit words to a hex string
Crypto.be32sToHex = function(be)
{
	var hex = "0123456789ABCDEF";
	var str = "";
	for(var i=0;i<be.length*4;i++)
		str += hex.charAt((be[i>>2]>>((3-i%4)*8+4))&0xF) + hex.charAt((be[i>>2]>>((3-i%4)*8))&0xF);
	return str;
};

// Return, in hex, the SHA-1 hash of a string
Crypto.hexSha1Str = function(str)
{
	return Crypto.be32sToHex(Crypto.sha1Str(str));
};

// Return the SHA-1 hash of a string
Crypto.sha1Str = function(str)
{
	return Crypto.sha1(Crypto.strToBe32s(str),str.length);
};

// Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words
Crypto.sha1 = function(x,blen)
{
	// Add 32-bit integers, wrapping at 32 bits
	add32 = function(a,b)
	{
		var lsw = (a&0xFFFF)+(b&0xFFFF);
		var msw = (a>>16)+(b>>16)+(lsw>>16);
		return (msw<<16)|(lsw&0xFFFF);
	};
	// Add five 32-bit integers, wrapping at 32 bits
	add32x5 = function(a,b,c,d,e)
	{
		var lsw = (a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF)+(e&0xFFFF);
		var msw = (a>>16)+(b>>16)+(c>>16)+(d>>16)+(e>>16)+(lsw>>16);
		return (msw<<16)|(lsw&0xFFFF);
	};
	// Bitwise rotate left a 32-bit integer by 1 bit
	rol32 = function(n)
	{
		return (n>>>31)|(n<<1);
	};

	var len = blen*8;
	// Append padding so length in bits is 448 mod 512
	x[len>>5] |= 0x80 << (24-len%32);
	// Append length
	x[((len+64>>9)<<4)+15] = len;
	var w = Array(80);

	var k1 = 0x5A827999;
	var k2 = 0x6ED9EBA1;
	var k3 = 0x8F1BBCDC;
	var k4 = 0xCA62C1D6;

	var h0 = 0x67452301;
	var h1 = 0xEFCDAB89;
	var h2 = 0x98BADCFE;
	var h3 = 0x10325476;
	var h4 = 0xC3D2E1F0;

	for(var i=0;i<x.length;i+=16) {
		var j,t;
		var a = h0;
		var b = h1;
		var c = h2;
		var d = h3;
		var e = h4;
		for(j = 0;j<16;j++) {
			w[j] = x[i+j];
			t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1);
			e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
		}
		for(j=16;j<20;j++) {
			w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
			t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1);
			e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
		}
		for(j=20;j<40;j++) {
			w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
			t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k2);
			e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
		}
		for(j=40;j<60;j++) {
			w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
			t = add32x5(e,(a>>>27)|(a<<5),(b&c)|(d&(b|c)),w[j],k3);
			e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
		}
		for(j=60;j<80;j++) {
			w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
			t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k4);
			e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
		}

		h0 = add32(h0,a);
		h1 = add32(h1,b);
		h2 = add32(h2,c);
		h3 = add32(h3,d);
		h4 = add32(h4,e);
	}
	return Array(h0,h1,h2,h3,h4);
};


}
//}}}
/***
|''Name:''|DeprecatedFunctionsPlugin|
|''Description:''|Support for deprecated functions removed from core|
***/
//{{{
if(!version.extensions.DeprecatedFunctionsPlugin) {
version.extensions.DeprecatedFunctionsPlugin = {installed:true};

//--
//-- Deprecated code
//--

// @Deprecated: Use createElementAndWikify and this.termRegExp instead
config.formatterHelpers.charFormatHelper = function(w)
{
	w.subWikify(createTiddlyElement(w.output,this.element),this.terminator);
};

// @Deprecated: Use enclosedTextHelper and this.lookaheadRegExp instead
config.formatterHelpers.monospacedByLineHelper = function(w)
{
	var lookaheadRegExp = new RegExp(this.lookahead,"mg");
	lookaheadRegExp.lastIndex = w.matchStart;
	var lookaheadMatch = lookaheadRegExp.exec(w.source);
	if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
		var text = lookaheadMatch[1];
		if(config.browser.isIE)
			text = text.replace(/\n/g,"\r");
		createTiddlyElement(w.output,"pre",null,null,text);
		w.nextMatch = lookaheadRegExp.lastIndex;
	}
};

// @Deprecated: Use <br> or <br /> instead of <<br>>
config.macros.br = {};
config.macros.br.handler = function(place)
{
	createTiddlyElement(place,"br");
};

// Find an entry in an array. Returns the array index or null
// @Deprecated: Use indexOf instead
Array.prototype.find = function(item)
{
	var i = this.indexOf(item);
	return i == -1 ? null : i;
};

// Load a tiddler from an HTML DIV. The caller should make sure to later call Tiddler.changed()
// @Deprecated: Use store.getLoader().internalizeTiddler instead
Tiddler.prototype.loadFromDiv = function(divRef,title)
{
	return store.getLoader().internalizeTiddler(store,this,title,divRef);
};

// Format the text for storage in an HTML DIV
// @Deprecated Use store.getSaver().externalizeTiddler instead.
Tiddler.prototype.saveToDiv = function()
{
	return store.getSaver().externalizeTiddler(store,this);
};

// @Deprecated: Use store.allTiddlersAsHtml() instead
function allTiddlersAsHtml()
{
	return store.allTiddlersAsHtml();
}

// @Deprecated: Use refreshPageTemplate instead
function applyPageTemplate(title)
{
	refreshPageTemplate(title);
}

// @Deprecated: Use story.displayTiddlers instead
function displayTiddlers(srcElement,titles,template,unused1,unused2,animate,unused3)
{
	story.displayTiddlers(srcElement,titles,template,animate);
}

// @Deprecated: Use story.displayTiddler instead
function displayTiddler(srcElement,title,template,unused1,unused2,animate,unused3)
{
	story.displayTiddler(srcElement,title,template,animate);
}

// @Deprecated: Use functions on right hand side directly instead
var createTiddlerPopup = Popup.create;
var scrollToTiddlerPopup = Popup.show;
var hideTiddlerPopup = Popup.remove;

// @Deprecated: Use right hand side directly instead
var regexpBackSlashEn = new RegExp("\\\\n","mg");
var regexpBackSlash = new RegExp("\\\\","mg");
var regexpBackSlashEss = new RegExp("\\\\s","mg");
var regexpNewLine = new RegExp("\n","mg");
var regexpCarriageReturn = new RegExp("\r","mg");

}
//}}}
https://www.nordicsemi.com/Products/Development-hardware/Power-Profiler-Kit-2

^ python support

https://github.com/IRNAS/ppk2-api-python

.pre

pi@pihdmi:~/ppk2-api-python $ git remote -v
origin	https://github.com/IRNAS/ppk2-api-python (fetch)
origin	https://github.com/IRNAS/ppk2-api-python (push)

pi@pihdmi:~/ppk2-api-python $ sudo python3 setup.py install

.pre
{toc: }

{file: ESP32-Devkit-Pinout_19.pdf}

https://github.com/espressif/arduino-esp32/issues/544

^ ESP32 DEVKIT1

schematic: {file: SchematicsforESP32.pdf}

to get into bootloader mode (out of box) plug module in (red led will show that it has power from usb) and:

press EN - press BOOT - release EN - release BOOT

.pre
dpavlin@x200:/mnt/nuc/esptool$ ./esptool.py -p /dev/ttyUSB0 --chip esp32 read_mac
esptool.py v2.7-dev
Serial port /dev/ttyUSB0
Connecting........_
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 3c:71:bf:aa:fc:24
Uploading stub...
Running stub...
Stub running...
MAC: 3c:71:bf:aa:fc:24
Hard resetting via RTS pin...

dpavlin@x200:/mnt/nuc/esptool$ ./esptool.py -p /dev/ttyUSB0 --chip esp32 chip_id
esptool.py v2.7-dev
Serial port /dev/ttyUSB0
Connecting........__
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 3c:71:bf:aa:fc:24
Uploading stub...
Running stub...
Stub running...
Warning: ESP32 has no Chip ID. Reading MAC instead.
MAC: 3c:71:bf:aa:fc:24
Hard resetting via RTS pin...

dpavlin@x200:/mnt/nuc/esptool$ ./esptool.py -p /dev/ttyUSB0 --chip esp32 flash_id
esptool.py v2.7-dev
Serial port /dev/ttyUSB0
Connecting........_____....._____....._____....._____.
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 3c:71:bf:aa:fc:24
Uploading stub...
Running stub...
Stub running...
Manufacturer: 20
Device: 4016
Detected flash size: 4MB
Hard resetting via RTS pin...

.pre

^ setup

https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html#setup-toolchain

.pre
dpavlin@nuc:/nuc/esp32$ wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz

dpavlin@nuc:/nuc/esp32$ tar tvf xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz

dpavlin@nuc:/nuc/esp32$ git clone --recursive https://github.com/espressif/esp-idf.git

dpavlin@nuc:/nuc/esp32$ cd esp-idf/

dpavlin@nuc:/nuc/esp32/esp-idf$ cat env.sh 
export IDF_PATH=/nuc/esp32/esp-idf
export PATH=/nuc/esp32/xtensa-esp32-elf/bin/:$PATH
dpavlin@nuc:/nuc/esp32/esp-idf$ . env.sh 

dpavlin@nuc:/nuc/esp32/esp-idf$ python2 -m pip install --user -r $IDF_PATH/requirements.txt
Requirement already satisfied: setuptools in /usr/lib/python2.7/dist-packages (from -r /nuc/esp32/esp-idf/requirements.txt (line 4)) (40.6.2)
Requirement already satisfied: pyserial>=3.0 in /home/dpavlin/.local/lib/python2.7/site-packages (from -r /nuc/esp32/esp-idf/requirements.txt (line 8)) (3.4)
Requirement already satisfied: future>=0.15.2 in /usr/lib/python2.7/dist-packages (from -r /nuc/esp32/esp-idf/requirements.txt (line 9)) (0.15.2)
Requirement already satisfied: cryptography>=2.1.4 in /usr/lib/python2.7/dist-packages (from -r /nuc/esp32/esp-idf/requirements.txt (line 10)) (2.3)
Requirement already satisfied: pyparsing>=2.0.3 in /usr/lib/python2.7/dist-packages (from -r /nuc/esp32/esp-idf/requirements.txt (line 11)) (2.2.0)

.pre

^ WT32-ETH01

https://github.com/egnor/wt32-eth01
https://www.raspberrypi.com/documentation/microcontrollers/rp2040.html

^ python

https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf

^ 1.8TFT

ST7755

pinout of connector, rp2040 pins

VCC
GND
CS 17 SPI0 CSn
RESET 16 SPI0 MISO
A0 20 
SDA 19 SPI0 MOSI
SCK 18 SPI0 SCK
LED

https://github.com/boochow/MicroPython-ST7735

.pre
spi = SPI(0, baudrate=20000000, polarity=0, phase=0, sck=Pin(18), mosi=Pin(19), miso=Pin(16))
tft=TFT(spi,20,16,17)
.pre
{toc: }

^ first steps

Here I will try to document correct order to read documentation to get setup for ULX3S:

https://github.com/emard/ulx3s-bin/blob/master/README.md

There is also useful things from chat at [ULX3S Lobby]

^^ udev rule

^^ ujprog

.pre
git clone https://github.com/f32c/tools f32c-tools
cd f32c-tools/ujprog/
dpavlin@x200:/mnt/nuc/FPGA/f32c-tools/ujprog$ rm ujprog
dpavlin@x200:/mnt/nuc/FPGA/f32c-tools/ujprog$ make -f Makefile.linux
cc -Wall -D__linux__ -std=gnu99 -static ujprog.c /usr/lib/x86_64-linux-gnu/libftdi.a /usr/lib/x86_64-linux-gnu/libusb.a -o ujprog
dpavlin@x200:/mnt/nuc/FPGA/f32c-tools/ujprog$ sudo cp ujprog /usr/local/bin/
.pre

* create udev rule

^^ passthru to access esp32

source at https://github.com/emard/ulx3s-passthru

.pre
dpavlin@x200:/mnt/nuc/FPGA/ulx3s-bin/fpga/passthru/passthru-v20-85f$ ujprog -j flash ulx3s_85f_passthru.bit
ULX2S / ULX3S JTAG programmer v 3.0.92 (built Nov 19 2019 10:55:50)
Using USB cable: ULX3S FPGA 12K v3.0.3
[Wed Nov 20 18:02:01 2019] ftdi_sio ttyUSB0: FTDI USB Serial Device converter now disconnected from ttyUSB0
[Wed Nov 20 18:02:01 2019] ftdi_sio 1-5.2:1.0: device disconnected
Programming: 100%
Completed in 24.36 seconds.
[Wed Nov 20 18:02:25 2019] usb 1-5.2: reset full-speed USB device number 56 using ehci-pci
[Wed Nov 20 18:02:26 2019] ftdi_sio 1-5.2:1.0: FTDI USB Serial Device converter detected
[Wed Nov 20 18:02:26 2019] usb 1-5.2: Detected FT-X
[Wed Nov 20 18:02:26 2019] usb 1-5.2: FTDI USB Serial Device converter now attached to ttyUSB0

.pre

^^ update size of your FPGA

.pre
dpavlin@x200:/mnt/nuc/FPGA/ulx3s-bin$ usb-jtag/linux-amd64/ftx_prog --product "ULX3S FPGA 85K v3.0.3"
.pre

power cycle board to get new usb id, test that it's supported by ujprog

.pre
dpavlin@x200:/mnt/nuc/FPGA/ulx3s-bin$ ujprog -r
.pre

^^ esptool and esp32 booting problems

You should be using ecptool from ulx3s-bin repository to quite @emard from https://gitter.im/ulx3s/Lobby#dark-theme

> OK then. If you have issues with ESP32 not booting with SD card but booting without SD card then then the fuse burn script from ulx3s-bin should be run. So far so good, you erased its flash, try linux. If no issue then can try to flash micropython and my new ESP32 OTA programmer ecp5.py end uftpd.py

> I have wisely taken some esptool.py which works and frozen it in ulx3s, versions change all the time and maybe you took something in the middle of development action :)

^^ install micropython

https://github.com/emard/esp32ecp5/

.pre
dpavlin@nuc:/nuc/FPGA$ git clone https://github.com/emard/esp32ecp5/
dpavlin@nuc:/nuc/FPGA$ cd esp32ecp5/
dpavlin@x200:/mnt/nuc/FPGA/esp32ecp5$ wget https://micropython.org/resources/firmware/esp32-idf3-20191120-v1.11-580-g973f68780.bin

.pre

It's important to erase flash or micropyhton will complain about corrupt fat filesystem like:

FAT filesystem appears to be corrupted. If you had important data there, you
may want to make a flash snapshot to try to recover it. Otherwise, perform
factory reprogramming of MicroPython firmware (completely erase flash, followed
by firmware programming).

.pre
dpavlin@x200:/mnt/nuc/FPGA/esp32ecp5$ ../ulx3s-bin/esp32/serial-uploader/esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash
esptool.py v2.6-beta1
Serial port /dev/ttyUSB0
Connecting....
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: a4:cf:12:55:c5:60
Uploading stub...
Running stub...
Stub running...
Erasing flash (this may take a while)...
Chip erase completed successfully in 8.7s
Hard resetting via RTS pin...


dpavlin@x200:/mnt/nuc/FPGA/esp32ecp5$ ../ulx3s-bin/esp32/serial-uploader/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 write_flash -z 0x1000 esp32-idf3-20191120-v1.11-580-g973f68780.bin
esptool.py v2.6-beta1
Serial port /dev/ttyUSB0
Connecting....
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: a4:cf:12:55:c5:60
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 1240192 bytes to 783187...
Wrote 1240192 bytes (783187 compressed) at 0x00001000 in 18.7 seconds (effective 529.3 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

dpavlin@x200:/mnt/nuc/FPGA/esp32ecp5$ microcom -p /dev/ttyUSB0
connected to /dev/ttyUSB0
Escape character: Ctrl-\
Type the escape character to get to the prompt.

>>>
> help()
Welcome to MicroPython on the ESP32!

For generic online docs please visit http://docs.micropython.org/

For access to the hardware use the 'machine' module:

import machine
pin12 = machine.Pin(12, machine.Pin.OUT)
pin12.value(1)
pin13 = machine.Pin(13, machine.Pin.IN, machine.Pin.PULL_UP)
print(pin13.value())
i2c = machine.I2C(scl=machine.Pin(21), sda=machine.Pin(22))
i2c.scan()
i2c.writeto(addr, b'1234')
i2c.readfrom(addr, 4)

Basic WiFi configuration:

import network
sta_if = network.WLAN(network.STA_IF); sta_if.active(True)
sta_if.scan()                             # Scan for available access points
sta_if.connect("<AP_name>", "<password>") # Connect to an AP
sta_if.isconnected()                      # Check for successful connection

Control commands:
  CTRL-A        -- on a blank line, enter raw REPL mode
  CTRL-B        -- on a blank line, enter normal REPL mode
  CTRL-C        -- interrupt a running program
  CTRL-D        -- on a blank line, do a soft reset of the board
  CTRL-E        -- on a blank line, enter paste mode

For further help on a specific object, type help(obj)
For a list of available modules, type help('modules')
.pre

^^ webrepl

.pre
dpavlin@klin:/klin/FPGA$ git clone https://github.com/hyperglitch/webrepl


.pre

You can send files from command-line:

.pre
dpavlin@x200:/mnt/nuc/FPGA/webrepl$ ./webrepl_cli.py -p ulx3s ../esp32ecp5/ecp5.py 192.168.3.130:/
op:put, host:192.168.3.130, port:8266, passwd:ulx3s.
../esp32ecp5/ecp5.py -> /ecp5.py
Remote WebREPL version: (1, 11, 0)
Sent 22777 of 22777 bytes
dpavlin@x200:/mnt/nuc/FPGA/webrepl$ ./webrepl_cli.py -p ulx3s ../esp32ecp5/uftpd.py 192.168.3.130:/
op:put, host:192.168.3.130, port:8266, passwd:ulx3s.
../esp32ecp5/uftpd.py -> /uftpd.py
Remote WebREPL version: (1, 11, 0)
Sent 19482 of 19482 bytes

.pre

^ open source toolchain

Just use kost's binary builds: https://github.com/alpin3/ulx3s/releases

Or nightly builds: https://github.com/open-tool-forge/fpga-toolchain/releases

*this is old and needs update*

* https://github.com/SymbiFlow/prjtrellis

.pre
dpavlin@klin:/klin/FPGA$ git clone https://github.com/SymbiFlow/prjtrellis
dpavlin@klin:/klin/FPGA/prjtrellis$ ./download-latest-db.sh 

dpavlin@klin:/klin/FPGA/prjtrellis$ cd libtrellis/
dpavlin@klin:/klin/FPGA/prjtrellis/libtrellis$ sudo apt-get install libpython3-dev libboost-python-dev libboost-filesystem-dev libboost-thread-dev libboost-program-options-dev
dpavlin@klin:/klin/FPGA/prjtrellis/libtrellis$ cmake -DCMAKE_INSTALL_PREFIX=/usr/local .
dpavlin@klin:/klin/FPGA/prjtrellis/libtrellis$ make
sudo make install


dpavlin@klin:/klin/FPGA/nextpnr$ cmake -DARCH=ecp5 -DBUILD_GUI=OFF -DTRELLIS_ROOT=../prjtrellis/ .
make
make install




.pre

^ diamond

https://github.com/jandob/lattice-diamond-archlinux/blob/master/eth0DummyToggle

^^ docker

https://gitter.im/ulx3s/Lobby?at=5dff4b08d2dadb38935c570a

https://github.com/dok3r/diamond/

.pre
docker run -it -v /host/fpga:/fpga -- local /host/fpga will end up in /fpga in docker

yes path will be fine
you will be missing make
so inside container you need to yum install make
and yum install libxslt
export ETHMAC=b0:5a:da:XX:XX:XX
set your MAC
docker run -it -v /media/internal/FPGA:/fpga -e LM_LICENSE_FILE=/fpga/license.dat --mac-address=$ETHMAC --privileged --ipc host -v /dev/bus/usb/:/dev/bus/usb/ dok3r/diamond:latest
run docker
yum install make libxslt
go tu project inside fpga folder and find makefile for diamond and then just make

then you share it with docker container with -v /yourHOSTfpgadir:/fpgadockerdir -e LM_LICENSE_FILE=/fpgadockerdir
for version you need to use like this dok3r/diamond:version
versions are here
https://hub.docker.com/r/dok3r/diamond/tags
docker run -it -v /media/internal/FPGA:/fpga -e LM_LICENSE_FILE=/fpga/license.dat --mac-address=$ETHMAC --privileged --ipc host -v /dev/bus/usb/:/dev/bus/usb/ dok3r/diamond:v3.7
like this
Not understanding -v /media/internal/FPGA
that is my local FPGA folder with samples and license.dat
it will mount on docker /fpga
and I see now that I need to share prjtrallis folder to docker so it can do ecppll
docker run -it -v /media/internal/FPGA:/fpga -v /local/prjtrellis/libtrellis:/mt/scratch/tmp/openfpga/prjtrellis/libtrellis -e LM_LICENSE_FILE=/fpga/license.dat --mac-address=$ETHMAC --privileged --ipc host -v /dev/bus/usb/:/dev/bus/usb/ dok3r/diamond:v3.7
but for that we will need @kost
we probably need ecppll and tools already there and compiled with centos- maybe just binaries
.pre

^ NES

https://gitter.im/ulx3s/Lobby?at=5de033f49319bb5190a9c3b6

* https://github.com/ironsteel/nes_ecp5
* flash arbitrary data to flash: https://github.com/ironsteel/tools/commit/cb0c43b6681a52f1cc19b6b70ddd587a307da90c#diff-3b94c2a26ac88b4b2363e058acf1852fR2281
* list of idcode: https://github.com/SymbiFlow/prjtrellis/blob/master/devices.json

* ported to ulx3s: https://github.com/lawrie/nes_ecp5

^ oberon

https://gitter.im/ulx3s/Lobby?at=5e007d1e8897197969e3331c

So, I have now managed to build oberon with diamond 3.7.
What I have to do is:

1. Build it with diamond 3.11, which fails
2. mv clocks clocks_save
3. make clean 
4. cp -r clocks_save clocks
5. run docker for diamond 3.7
6. edit synpbase/bin/config/platform_check to allow 5.* linux.
7. make
8. Use ujprog in host linux to upload generated bit file

Thanks @kost for adding for adding make and libxslt to the docker image. It would be useful if you could patch the platform_check to allow versions before 3.11 to run on 5.* linux.
I got a lot of errors in the diamond 3.7 docker build, but the .bit file was created.
I can now run oberon and can see windows on the screen, but I don't have a working mouse or keyboard. I would need Goran's USB board to get both mouse and keyboard.
@lawrie i fixed in latest v3.7 - just make sure that you're running latest:

docker pull dok3r/diamond:v3.7

woohoo! Cool
@kost I pulled the latest v3.7 about 10 minutes ago, but still had to edit platform_check.
synpbase/bin/config/platform_check has:

        case $VERSION in
            4.* | 3.* | 2.4.* | 2.6.* )

It needs:

        case $VERSION in
            5.* | 4.* | 3.* | 2.4.* | 2.6.* )

I did the docker pull to make sure I had the latest version.
I changed oberon makefile to generate clocks in already existing directory to get rid of annoying mkdir clocks
In my instructions above it is safer to do make ECPPLL=echo in docker, so that it does not try to use ecppll, but uses the saved clocks that were generated on host linux.

^ 21f repack from 25f image

.pre
ecpunpack --input ulx3s_25.bit --textcfg ulx3s_12f.config --idcode 0x41111043
ecppack --input ulx3s_12f.config --bit ulxs3_12f.bit --idcode 0x21111043

.pre

^ compress bitstream

.pre
ecppack --compress
.pre

^ esp32ps2

https://github.com/emard/esp32ps2

^ saxonsoc

^^ linux

Instructions at https://github.com/lawrie/saxonsoc-ulx3s-bin/tree/master/linux
work for me on 85f :-)

https://gitter.im/ulx3s/Lobby?at=5de8ba2f08d0c961b7f3a25f

.pre
git clone https://github.com/SpinalHDL/buildroot.git -b saxon buildroot
git clone https://github.com/SpinalHDL/linux.git -b vexriscv --depth 1 linux
cd buildroot
cp board/spinal/saxon_default/linux_nonet.config board/spinal/saxon_default/linux.config
# Add extra options to board/spinal/saxon_default/linux.config
make spinal_saxon_default_defconfig
make linux-rebuild all -j$(nproc)
output/host/bin/riscv32-linux-objcopy -O binary output/images/vmlinux output/images/Image
# Make sure Image is at least 116KB less than 4MB
.pre

^^ 85f version

https://gitter.im/ulx3s/Lobby?at=5dea74995ac7f22fb57055ae

https://github.com/lawrie/saxonsoc-ulx3s-bin/blob/master/linux/README.md

https://github.com/lawrie/saxonsoc-ulx3s-bin/tree/master/linux/u-boot

https://github.com/SpinalHDL/SaxonSoc/tree/dev/bsp/Ulx3sLinuxUboot

^^ leds

https://gitter.im/ulx3s/Lobby?at=5dec101f46397c721ca4c814

.pre
#!/bin/sh
cd /sys/class/gpio
echo 488 > export
echo out > gpio488/direction
for i in 1 0 1 0 1 0
do
  sleep  0.1
  echo   $i > gpio488/value
done

.pre

^^ slirp

https://gitter.im/ulx3s/Lobby?at=5df1467d0616d6515e20d197

^^ modifications

https://gitter.im/ulx3s/Lobby?at=5dfced993e3f133894ca9b4b

^^ u-boot config for 85f with 64M SDRAM

Modify bootcmd to include:

.pre
load mmc 0:1 0x80000000 /boot/uImage
load mmc 0:1 0x81EF0000 /boot/dtb
fdt add 0x81EF0000
fdt memory 0x80000000 0x04000000
bootm 0x80000000 - 0x81EF0000
.pre

^^ ppp networking

* https://github.com/dok3r/ulx3s-saxonsoc/wiki/ulx3s-networking
* https://github.com/emard/esp32ppp

^^ smp support

https://gitter.im/ulx3s/Lobby?at=5f4ea80bd4f0f55ebbf6ec33

https://github.com/SpinalHDL/SaxonSoc/tree/dev-0.1/bsp/radiona/ulx3s/smp

Instructions there need a bit of modification to run on blue 85f board with 64Mb of ram:

.pre
# Sourcing the build script
source SaxonSoc/bsp/radiona/ulx3s/smp/source.sh

# Clone opensbi, u-boot, linux, buildroot, openocd
saxon_clone

# Build the FPGA bitstream
saxon_standalone_compile bootloader CFLAGS_ARGS="-DSDRAM_TIMING=AS4C32M16SB_7TCN_ps"
SDRAM_SIZE=64 saxon_netlist
FPGA_SIZE=85 saxon_bitstream

# Build the firmware
saxon_opensbi
saxon_uboot
saxon_buildroot

# Build the programming tools
saxon_standalone_compile sdramInit CFLAGS_ARGS="-DSDRAM_TIMING=AS4C32M16SB_7TCN_ps"
saxon_openocd
.pre

Copy generated bitstream

.pre
dpavlin@klin:/klin/FPGA/saxonsoc$ cp SaxonSoc/hardware/synthesis/radiona/ulx3s/smp/bin/toplevel.bit saxon.bit
dpavlin@klin:/klin/FPGA/saxonsoc$ gzip -9 saxon.bit
.pre

Transfer it using ftp

.pre
ftp> put saxon.bit.gz
local: saxon.bit.gz remote: saxon.bit.gz
200 OK
150 Opened data connection.
226 Done.
359484 bytes sent in 10.27 secs (34.1994 kB/s)
ftp> site saxon.bit.gz
.pre

u-boot will fail to boot if you have rootfs on second partition

.pre
SDRAM init
OpenSBI copy
U-Boot copy
OpenSBI boot

OpenSBI v0.6-8-gd7b62b8
   ____                    _____ ____ _____
  / __ \                  / ____|  _ \_   _|
 | |  | |_ __   ___ _ __ | (___ | |_) || |
 | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
 | |__| | |_) |  __/ | | |____) | |_) || |_
  \____/| .__/ \___|_| |_|_____/|____/_____|
        | |
        |_|

Platform Name          : VexRiscv SMP simulation
Platform HART Features : RV32AIMS
Platform Max HARTs     : 4
Current Hart           : 0
Firmware Base          : 0x80f80000
Firmware Size          : 84 KB
Runtime SBI Version    : 0.2

MIDELEG : 0x00000222
MEDELEG : 0x0000b101


U-Boot 2020.07-08304-gd361dd3997 (Sep 05 2020 - 09:45:52 +0200)

DRAM:  32 MiB
MMC:   spi@10020000:mmc@1: 0
Loading Environment from FAT... Unable to use mmc 0:1... In:    serial@10010000
Out:   serial@10010000
Err:   serial@10010000
Net:   No ethernet found.
Hit any key to stop autoboot:  0
Wrong Image Format for bootm command
ERROR: can't get kernel image!
=>
.pre

https://github.com/dok3r/ulx3s-saxonsoc/wiki/SaxonSoc-on-ULX3s

.pre
setenv bootcmd "load mmc 0:1 0x80000000 /boot/uImage;load mmc 0:1 0x80FF0000 /boot/dtb;fdt add 0x80FF0000;fdt memory 0x80000000 0x04000000;bootm 0x80000000 - 0x80FF0000"
setenv bootargs "rootwait console=hvc0 root=/dev/mmcblk0p2 init=/sbin/init mmc_core.use_spi_crc=0"
saveenv
.pre

> Lawrie Griffiths @lawrie Sep 01 21:59

The new SaxonSoc is now working on a 12F for me. Here are the instructions to build from source - https://github.com/SpinalHDL/SaxonSoc/tree/dev-0.1/bsp/radiona/ulx3s/smp
The images and bitstream are here - https://github.com/lawrie/saxonsoc-ulx3s-bin/tree/master/Smp
There is no sdcard image at the moment, but all the files are there for you to build your own.

^ ov7670 pmod

https://github.com/goran-mahovlic/fpga-odysseus/tree/master/projects/OV7670-HDMI

pmod pin mapping:

https://github.com/goran-mahovlic/fpga-odysseus/blob/master/projects/OV7670-HDMI/ulx3s.lpf#L335

^^ SCCB Pullup Resistors

from https://github.com/westonb/OV7670-Verilog

The SCCB interface for the camera requires pull up resistors. You need to solder 4.7K resistors from the SIOD and SIOC pins on the camera to the 3.3V supply. You can do this yourself or have the staff in the EDS help you.

^^ ov7670_rgb_yuv_320x240_colorfilter

https://github.com/JdeRobot/FPGA-robotics/tree/master/Projects/ComputerVision

^^ nmigen

https://github.com/lawrie/ulx3s-nmigen-examples/blob/master/image/camtest.py

^ csi

https://twitter.com/mad_archer_/status/1231249513509261313

https://github.com/libv/fosdem-video-linux

^ litex

(just links, need to test it)

* https://gojimmypi.blogspot.com/2020/03/litex-soft-cpu-on-ulx3s-reloading.html
* https://github.com/timvideos/litex-buildenv/wiki/LiteX-for-Hardware-Engineers
* https://github.com/enjoy-digital/litex

^ spiram

https://gitter.im/ulx3s/Lobby?at=5ef22d4c54d7862dc4a42395

@Speccery thereis also commandline "spiram.py" for some low-level inspection, so to reset TI this works for me

>>> spiram.poke(0x100008,bytearray([0xFC]))
>>> spiram.poke(0x100008,bytearray([0xFF]))

and to read bytes

>>> spiram.peek(0,16)

bytearray(b'\x83\xe0\x00$\x83\xc0\t\x00\x83\xc0\n\x920\xaa\x04`')

^ led

.pre
ftx_prog --cbus 3 DRIVE_0 # green OFF

ftx_prog --cbus 3 SLEEP # green ON if enumerated
.pre

This is active after power cycle

^^ micropython blue led

.pre
>>> from machine import Pin
>>> led=Pin(5,Pin.OUT)
>>> led.on() # upali plavu
>>> led.off() # ugasi plavu
.pre

^ micropython

.pre
from upysh import *

.pre

^ TODO

try various projects for ulx3s

* https://gitlab.com/pnru/cortex

^ c64

part of https://github.com/lawrie/ulx3s_retro

https://github.com/emard/ulx3s_c64

.pre
dpavlin@klin:/klin/FPGA/ulx3s_c64/proj$ time make FPGA_SIZE=25



.pre

^ tfmicro on LiteX/VexRiscv

https://github.com/dlobato/tfmicro-on-litex-vexriscv

^ ML CNN accelerator

https://github.com/BracketMaster/maeri

^ kianRiscV

https://gitAhub.com/splinedrive/kianRiscV/tree/master/linux_socs/kianv_mc_rv32ima_sv32/demo

openFPGALoader -f -o $((1024*1024)) --board=ulx3s bootloader.bin
{toc: }

^ info

https://hackaday.com/2020/12/08/exploring-custom-firmware-on-xiaomi-thermometers/

https://github.com/atc1441/ATC_MiThermometer

https://github.com/pvvx/ATC_MiThermometer

 Xiaomi Smart LCD Screen Digital Thermometer 2 Mijia Bluetooth Temperature Humidity Sensor Moisture Meter Mijia App

https://www.aliexpress.com/item/1005002401046796.html

LYWSD03MMC

^ decode using gatttool

https://ndimension.design.blog/2021/12/16/reading-data-from-xiaomi-mi-temperature-and-humidity-monitor-2-lywsd03mmc/

.pre
root@rpi2:/home/pi# sudo hcitool lescan
LE Scan ...
A4:C1:38:D8:3F:9C ATC_D83F9C

.pre

^ open source firmware

https://github.com/bentolor/xiaomi-mijia-bluetooth-firmware

^ simple shell to send reading to influx

https://github.com/dpavlin/air-quality/blob/master/ble-mijia.sh

https://github.com/dpavlin/air-quality/blob/master/system/ble-mijia%40.service

https://www.youtube.com/watch?v=NXKzFG61lNs

^ [Home Assistant]

connected to home assistant using https://esphome.github.io/bluetooth-proxies/

get bindkey using https://atc1441.github.io/TelinkFlasher.html

https://esphome.io/components/sensor/xiaomi_ble.html?highlight=xiaomi_ble#obtaining-the-bindkey

.pre
[core-ssh ~]$ tail -18 config/.storage/core.config_entries
      {
        "entry_id": "574243c45c4485523ec174e18cfcf1ad",
        "version": 1,
        "domain": "xiaomi_ble",
        "title": "Temperature/Humidity Sensor DC63 (LYWSD03MMC)",
        "data": {
          "bindkey": "a6da0c1d99200efe9c9afb8fd9a534ef"
        },
        "options": {},
        "pref_disable_new_entities": false,
        "pref_disable_polling": false,
        "source": "bluetooth",
        "unique_id": "A4:C1:38:90:DC:63",
        "disabled_by": null
      }
    ]
  }
.pre

flash new firmware to sensor https://github.com/pvvx/ATC_MiThermometer

open in chrome on android to flash firmware,
change announcement to BTHome,
set time,
disconnect to start sending data to home assistant
{toc: }

{file: dove-bootlog.txt}

Xtreme PC LXD8541

Chip PC Linux-based Thinx OS

Product Specifications Xtreme PC LXD8541

Processor • Marvell Dove, Armada 510 800MHZ https://www.kernel.org/doc/html/v5.14/arm/marvell.html#dove-family-application-processor

Memory • 1GB, DDR3 @ 800MHz

Mass Storage • 2GB, High reliability eMMC NAND flash • Optional externally accessed MicroSD slot

Display Support • One DVI-I port
• Display Data Control (DDC) for automatic setting of resolution and refresh rate

Resolutions • Single: Up to 1920x1200 Pixels @ true color (32 bit)
• Dual: Up to 1920x1080 Pixels @ true color (24 bit)

Video Player • Various video codecs, including: DivX HD, H.264 (MPEG4), WMV9/VC1
• Up to 1080p local browser Flash support

Audio Support • High Definition Audio Codec
• Stereo Audio Output - 3 mm (1/8 inch) Audio-Out Jack; 16-bit Stereo, 96KHz

sample rate
• Microphone Input - 3 mm (1/8 inch), 8 bit
• Software volume / mute control

Input / Output ports • 6 x USB 2.0 ports (2 front, 4 back)

^ serial

https://forum.doozan.com/read.php?2,67954,76099#msg-76099

 Koen Re: Debian on Chip PC LXD8941 January 04, 2019 02:33PM

Inside there is both a 4 pin and a 6 pin header. The 4 pin is the UART connection. With the power button towards you and the DVI connection away from you the connections are as follows: GND, TX, RX, VCC (from left to right).

^ kernel

Linux Kernel 6.6.2 MVEBU package and Debian armhf rootfs

https://forum.doozan.com/read.php?2,32146

.pre
mkfs.ext3 -L rootfs /dev/sda1
mount /dev/sda1 /mnt/sda1/
cd /mnt/sda1/
tar xvf /nuc/armada/Debian-6.6.2-mvebu-tld-1-rootfs-bodhi.tar.bz2
.pre

3. Create uImage with DTB appended.

.pre
root@nuc:/mnt/sda1# cd boot/
root@nuc:/mnt/sda1/boot# cp -a uImage uImage.orig
root@nuc:/mnt/sda1/boot# cp -a zImage-6.6.2-mvebu-tld-1 zImage.fdt
root@nuc:/mnt/sda1/boot# cat dts/dove-chip-lxd8941.dtb >> zImage.fdt
root@nuc:/mnt/sda1/boot# mkimage -A arm -O linux -T kernel -C none -a 0x00008000 -e 0x00008000 -n Linux-6.6.2-mvebu-tld-1 -d zImage.fdt uImage
Image Name:   Linux-6.6.2-mvebu-tld-1
Created:      Tue Dec 19 18:00:34 2023
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    5193798 Bytes = 5072.07 KiB = 4.95 MiB
Load Address: 00008000
Entry Point:  00008000
.pre

insert usb stick into back 4 usb ports, front 2 won't find storage device on usb

abort u-boot over serial and issue boot from usb:

.pre
setenv bootargs console=ttyS0,115200 root=LABEL=rootfs rootdelay=10 ${mtdparts} earlyprintk=serial
usb start; ext2load usb 0:1 0x3000000 /boot/uImage; ext2load usb 0:1 0x4000000 /boot/uInitrd
bootm 0x3000000 0x4000000
.pre

^ video output

DRM and framebuffer are not currently (as of 6.6) supported in upstream kernel according to messages at
forum, but dove-chip-lxd8941.dts doesn't include lcd power and dove-hp-t5335z.dts does.

Let's try to boot with this dts but this does not work.

^ u-boot enviroment

^^ fw_printenv

.pre
root@dove:~# cat /etc/fw_env.config
# MTD device name       Device offset   Env. size       Flash sector size       Number of sectors
/dev/mtd1 0x000000 0x010000
.pre

^^ setup boot from usb

.pre
root@dove:~# fw_setenv bootusb 'setenv bootargs console=ttyS0,115200 root=LABEL=rootfs rootdelay=10 ${mtdparts} earlyprintk=serial ; usb start; ext2load usb 0:1 0x3000000 /boot/uImage; ext2load usb 0:1 0x4000000 /boot/uInitrd ; bootm 0x3000000 0x4000000'

root@dove:~# fw_printenv bootcmd
bootcmd=run bootmmc
root@dove:~# fw_setenv bootcmd bootusb
.pre

fw_setenv this doesn't work from booted debian system, re-try over serial on u-boot prompt:

.pre
MIC>> printenv usbboot
usbboot=usb start; sleep 3; ext2load usb 0:1 0x2000000 /boot/uImage; run usbargs;bootm 0x2000000
MIC>> setenv usbboot 'setenv bootargs console=ttyS0,115200 root=LABEL=rootfs rootdelay=10 ${mtdparts} earlyprintk=serial ; usb start; ext2load usb 0:1 0x3000000 /boot/uImage; ext2load usb 0:1 0x4000000 /boot/uInitrd ; bootm 0x3000000 0x4000000'
MIC>> printenv usbboot
usbboot=setenv bootargs console=ttyS0,115200 root=LABEL=rootfs rootdelay=10 ${mtdparts} earlyprintk=serial ; usb start; ext2load usb 0:1 0x3000000 /boot/uImage; ext2load usb 0:1 0x4000000 /boot/uInitrd ; bootm 0x3000000 0x4000000
MIC>> saveenv
Saving Environment to SPI Flash...
Erasing 0xc0000 - 0xd0000:      [Done]
Writing to SPI flash:           [Done]

MIC>> setenv bootcmd run usbboot
MIC>> saveenv
Saving Environment to SPI Flash...
Erasing 0xc0000 - 0xd0000:      [Done]
Writing to SPI flash:           [Done]

.pre

^ power button

seemes like it's on gpio 25

.pre
apt install gpiod

root@dove:/home/dpavlin# gpioget 0 0 1 2 3 4 5 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
1 0 1 1 0 0 0 0 1 1 1 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0
root@dove:/home/dpavlin# gpioget 0 0 1 2 3 4 5 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
1 0 1 1 0 0 0 0 1 1 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0

root@dove:/home/dpavlin# gpiomon 0 25
event: FALLING EDGE offset: 25 timestamp: [    1466.369262333]
event: FALLING EDGE offset: 25 timestamp: [    1466.632278096]
event:  RISING EDGE offset: 25 timestamp: [    1467.188375662]
event:  RISING EDGE offset: 25 timestamp: [    1468.390585489]
event: FALLING EDGE offset: 25 timestamp: [    1470.143645190]
event:  RISING EDGE offset: 25 timestamp: [    1471.752436499]
event: FALLING EDGE offset: 25 timestamp: [    1473.233499601]
event:  RISING EDGE offset: 25 timestamp: [    1474.560678725]
.pre
^ TV power button

.pre
show_name: true
show_icon: true
type: button
tap_action:
  action: call-service
  service: mqtt.publish
  data:
    topic: cmnd/ir/IRSend
    payload: '{"protocol": "NEC","bits": 32, "data": 0x20DF10EF}'
  target: {}
icon: mdi:television
.pre
{toc: }

https://github.com/raphaelbs/esp32-cam-ai-thinker/blob/master/docs/about-esp32-cam.md

^ connection, flashing

connected to pl2303 serial

| pl2303 | esp32cam |
| 3v3 | not connected |
| rxd | UnR |
| rxd | UOT |
| gnd | GND |
| 5v | 5V |

{image: ESP32-CAM-pinout-new.png}

To program the board, I userd jumper to jump GPIO0 with GND pin next to it.

^ improved example app

https://github.com/easytarget/esp32-cam-webserver

.pre
   cp myconfig.sample.h myconfig.h
   vi myconfig.h
dpavlin@nuc:/nuc/esp32/esp32-cam-webserver$ platformio run

dpavlin@nuc:/nuc/esp32/esp32-cam-webserver$ pio run -t upload --upload-port /dev/ttyUSB2
"/home/dpavlin/.platformio/penv/bin/python" "/home/dpavlin/.platformio/packages/tool-esptoolpy/esptool.py" \
--chip esp32 --port "/dev/ttyUSB3" --baud 460800 --before default_reset --after hard_reset \
write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect \
0x1000 /home/dpavlin/.platformio/packages/framework-arduinoespressif32/tools/sdk/bin/bootloader_dio_40m.bin \
0x8000 /nuc/esp32/esp32-cam-webserver/.pio/build/esp32cam/partitions.bin \
0xe000 /home/dpavlin/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin \
0x10000 .pio/build/esp32cam/firmware.bin
.pre

^ timelapse

* https://bitluni.net/esp32camtimelapse
* https://github.com/bitluni/ESP32CamTimeLapse

^ ocr on device

https://github.com/jomjol/AI-on-the-edge-device

https://github.com/jomjol/AI-on-the-edge-device/wiki/Installation

Remove glue from lens (very hard, using sharp knife), and rotate lens by 45 degrees until
picture is sharp (I had to use pliers to do this).

.pre
dpavlin@nuc:/nuc/esp32/AI-on-the-edge-device$ vi sd-card/wlan.ini

dpavlin@nuc:/nuc/esp32/AI-on-the-edge-device/code$ pio run

dpavlin@nuc:/nuc/esp32/AI-on-the-edge-device/code$ pio run -v -t upload --upload-port /dev/ttyUSB3

"/home/dpavlin/.platformio/penv/bin/python" "/home/dpavlin/.platformio/packages/tool-esptoolpy/esptool.py" \
--chip esp32 --port "/dev/ttyUSB3" --baud 460800 --before default_reset --after hard_reset \
write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect \
0x1000 /nuc/esp32/AI-on-the-edge-device/code/.pio/build/esp32cam/bootloader.bin \
0x8000 /nuc/esp32/AI-on-the-edge-device/code/.pio/build/esp32cam/partitions.bin \
0xd000 /nuc/esp32/AI-on-the-edge-device/code/.pio/build/esp32cam/ota_data_initial.bin \
0x10000 .pio/build/esp32cam/firmware.bin

# original flashing instructions
esptool write_flash 0x01000 bootloader.bin 0x08000 partitions.bin 0x10000 firmware.bin

# download raw picture
wget 192.168.3.112/img_tmp/raw.jpg

.pre

----

^ old, obsolete problems

It seems that my module is usually known as AI thinker variant. It has terrible picture which starts with huge green bias.

It also doesn't work for me in resolutions below 1024x768 (in current esp32 example as of 2019-08-02).

Plugging it into external 5V power supply did not helped much.

----

To solve green tint, I just left esp32cam module plugged in whole day and night. I guess that image sensor got discharged during night, but next day picture was fine.

Problem with image resolution was fixed by updating to more recent version of ESP32 support for Arduino (as of 2020-04-20 it works fine)

^ [Home Assistant]

https://jamesachambers.com/cheap-esp32-cam-home-assistant-esphome-camera-guide/

.pre
esphome:
  name: esp32cam
  friendly_name: esp32cam

esp32:
  board: esp32cam
  framework:
    type: arduino

# Enable logging
logger:
  level: VERBOSE
  tx_buffer_size: 256

# Enable Home Assistant API
api:
  encryption:
    key: "MsJJJiDv9FTjZ1w8dfoy3Z8cQWjGOsk0m4Wgge0B+8w="
  services:  # change camera parameters on-the-fly
  - service: camera_set_param
    variables:
      name: string
      value: int
    then:
      - lambda: |-
          bool state_return = false;
          if (("contrast" == name) && (value >= -2) && (value <= 2)) { id(espcam).set_contrast(value); state_return = true; }
          if (("brightness" == name) && (value >= -2) && (value <= 2)) { id(espcam).set_brightness(value); state_return = true; }
          if (("saturation" == name) && (value >= -2) && (value <= 2)) { id(espcam).set_saturation(value); state_return = true; }
          if (("special_effect" == name) && (value >= 0U) && (value <= 6U)) { id(espcam).set_special_effect((esphome::esp32_camera::ESP32SpecialEffect)value); state_return = true; }
          if (("aec_mode" == name) && (value >= 0U) && (value <= 1U)) { id(espcam).set_aec_mode((esphome::esp32_camera::ESP32GainControlMode)value); state_return = true; }
          if (("aec2" == name) && (value >= 0U) && (value <= 1U)) { id(espcam).set_aec2(value); state_return = true; }
          if (("ae_level" == name) && (value >= -2) && (value <= 2)) { id(espcam).set_ae_level(value); state_return = true; }
          if (("aec_value" == name) && (value >= 0U) && (value <= 1200U)) { id(espcam).set_aec_value(value); state_return = true; }
          if (("agc_mode" == name) && (value >= 0U) && (value <= 1U)) { id(espcam).set_agc_mode((esphome::esp32_camera::ESP32GainControlMode)value); state_return = true; }
          if (("agc_value" == name) && (value >= 0U) && (value <= 30U)) { id(espcam).set_agc_value(value); state_return = true; }
          if (("agc_gain_ceiling" == name) && (value >= 0U) && (value <= 6U)) { id(espcam).set_agc_gain_ceiling((esphome::esp32_camera::ESP32AgcGainCeiling)value); state_return = true; }
          if (("wb_mode" == name) && (value >= 0U) && (value <= 4U)) { id(espcam).set_wb_mode((esphome::esp32_camera::ESP32WhiteBalanceMode)value); state_return = true; }
          if (("test_pattern" == name) && (value >= 0U) && (value <= 1U)) { id(espcam).set_test_pattern(value); state_return = true; }
          if (true == state_return) {
            id(espcam).update_camera_parameters();
          }
          else {
            ESP_LOGW("esp32_camera_set_param", "Error in name or data range");
          }

ota:
  password: "09e4b58a1d186b8b33d100548f33d796"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  power_save_mode: none

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Esp32Cam Fallback Hotspot"
    password: "GTIKgjitx2Re"

captive_portal:

# Example configuration entry
esp32_camera:
  id: espcam
  name: esp-cam
  external_clock:
    pin: GPIO0
    frequency: 20MHz
  i2c_pins:
    sda: GPIO26
    scl: GPIO27
  data_pins: [GPIO5, GPIO18, GPIO19, GPIO21, GPIO36, GPIO39, GPIO34, GPIO35]
  vsync_pin: GPIO25
  href_pin: GPIO23
  pixel_clock_pin: GPIO22
  power_down_pin: GPIO32

  resolution: 800x600
  jpeg_quality: 10  # max. 63
  max_framerate: 1.0fps
  idle_framerate: 0.2fps
  vertical_flip: true
  horizontal_mirror: false
  brightness: 2 # -2 to 2
  contrast: 1 # -2 to 2
  special_effect: none
  # exposure settings
  aec_mode: auto
  aec2: false
  ae_level: 0
  aec_value: 300
  # gain settings
  agc_mode: auto
  agc_gain_ceiling: 2x
  agc_value: 0
  # white balance setting
  wb_mode: auto
output:
# white LED
  - platform: ledc
    channel: 2
    pin: GPIO4
    id: espCamLED
# red status light
  - platform: gpio
    pin:
      number: GPIO33
      inverted: True
    id: gpio_33
light:
  - platform: monochromatic
    output: espCamLED
    name: esp-cam light
  - platform: binary
    output: gpio_33
    name: esp-cam led
switch:
  - platform: restart
    name: esp-cam restart
binary_sensor:
  - platform: status
    name: esp-cam status
.pre
CJMCU-811 CCS811 Carbon Monoxide CO VOCs Air Quality Digital Gas Sensor

https://revspace.nl/CJMCU-811

^ pins

    VCC this is directly connected to the IC (there is no voltage regulator on board), connect this to 3.3V
    GND to ground obviously
    SCL signal from I2C
    SDA signal from I2C
    WAK this needs to be low (!) in order for the chip to be active
    INT can be left unconnected
    RST can be left unconnected
    ADD can be left unconnected. It has a 10k pull-down to GND, setting the I2C address to 0x5A.

^ firmware upgrade

https://github.com/maarten-pennings/CCS811/tree/master/examples/ccs811flash

.pre
dpavlin@nuc:~/Arduino/libraries$ git clone https://github.com/maarten-pennings/CCS811

.pre

Wiring for ESP8266 NodeMCU boards: VDD to 3V3, GND to GND, SDA to D2, SCL to D1, nWAKE to D3 (or GND)

Serial output with sensor out of (china) bag:

.pre
setup: Starting CCS811 basic demo
setup: ccs811 lib  version: 12
setup: hardware    version: 12
setup: bootloader  version: 1000
setup: application version: 1100
CCS811: waiting for (new) data
CCS811: waiting for (new) data
CCS811: eco2=0 ppm  etvoc=0 ppb  
CCS811: eco2=0 ppm  etvoc=0 ppb  
CCS811: eco2=0 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
.pre

^^ upgrade serial output

.pre
Starting CCS811 flasher
setup: library     version: 12
setup: hardware    version: 12
setup: bootloader  version: 1000
setup: application version: 1100
setup: comment-out this code line if you want to flash
loop: ended ...
loop: ended ...
loop: ended ...
loop: ended ...
loop: ended ...
loop: ended ...
loop: ended ...
loop: ended ... 

ccs811: ping ok
ccs811: reset ok
ccs811: status (reset1) 10 ok
ccs811: app-erase ok
ccs811: status (app-erase) 40 ok
ccs811: writing 5120 ................................................................ 4608
ccs811: writing 4608 ................................................................ 4096
ccs811: writing 4096 ................................................................ 3584
ccs811: writing 3584 ................................................................ 3072
ccs811: writing 3072 ................................................................ 2560
ccs811: writing 2560 ................................................................ 2048
ccs811: writing 2048 ................................................................ 1536
ccs811: writing 1536 ................................................................ 1024
ccs811: writing 1024 ................................................................ 512
ccs811: writing 512 ................................................................ 0
ccs811: app-verify ok
ccs811: status (app-verify) 30 ok
ccs811: reset2 ok
ccs811: status (reset2) 10 ok

setup: Starting CCS811 basic demo
setup: ccs811 lib  version: 12
setup: hardware    version: 12
setup: bootloader  version: 1000
setup: application version: 2000
CCS811: waiting for (new) data
CCS811: waiting for (new) data
CCS811: waiting for (new) data
CCS811: waiting for (new) data
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=409 ppm  etvoc=1 ppb  
CCS811: eco2=414 ppm  etvoc=2 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=407 ppm  etvoc=1 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=408 ppm  etvoc=1 ppb  
CCS811: eco2=414 ppm  etvoc=2 ppb  
CCS811: eco2=417 ppm  etvoc=2 ppb  
CCS811: eco2=414 ppm  etvoc=2 ppb  
CCS811: eco2=408 ppm  etvoc=1 ppb  
CCS811: eco2=408 ppm  etvoc=1 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  
CCS811: eco2=406 ppm  etvoc=0 ppb  
CCS811: eco2=400 ppm  etvoc=0 ppb  

.pre

Since my sensor is new, I used firmware 2.0.0 to allow initial burn-in compensation.

^ temperature compensation

https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library/blob/master/examples/Example2_BME280Compensation/Example2_BME280Compensation.ino

^ esphome

.pre
esphome:
  name: ccs811
  friendly_name: ccs811

esp8266:
  board: nodemcuv2

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX="

ota:
  password: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Ccs811 Fallback Hotspot"
    password: "XXXXXXXXXXXX"

captive_portal:

  # Example configuration entry
i2c:
  sda: D2
  scl: D1

sensor:
  - platform: ccs811
    eco2:
      name: "CCS811 eCO2 Value"
    tvoc:
      name: "CCS811 Total Volatile Organic Compound"
    address: 0x5A
    update_interval: 15s

  - platform: bme280
    temperature:
      name: "BME280 Temperature"
      id: bme280_temperature
    pressure:
      name: "BME280 Pressure"
      id: bme280_pressure
    humidity:
      name: "BME280 Relative Humidity"
      id: bme280_humidity
    address: 0x76
    update_interval: 15s
.pre
RCWL-0516 is a doppler radar microwave motion sensor module which can act as an alternative to a PIR motion sensor.

https://github.com/jdesbonnet/RCWL-0516

https://community.home-assistant.io/t/custom-sensor-using-nodemcu-and-rcwl-0516-solved/313635/13
HDMI expander

* https://blog.danman.eu/new-version-of-lenkeng-hdmi-over-ip-extender-lkv373a/

* go implementation https://github.com/benjojo/de-ip-hdmi

* Sending audio to LKV373 HDMI extenders https://eta.st/2021/06/20/showtime.html
http://www.fnirsi.com.cn/home?lang=en-us

http://www.fnirsi.com.cn/product/704369228916068352

http://www.fnirsi.com.cn/download/usb

https://goughlui.com/2023/04/29/review-tested-fnirsi-fnb58-usb-fast-charge-tester/

^ usb serial

https://github.com/baryluk/fnirsi-usb-power-data-logger

^ ble

https://github.com/losonsky/FNB58

.pre
root@rpi4:/home/pi/FNB58# git remote -v
origin	https://github.com/losonsky/FNB58 (fetch)
origin	https://github.com/losonsky/FNB58 (push)
root@rpi4:/home/pi/FNB58# git diff
diff --git a/fnb58_dump.sh b/fnb58_dump.sh
index 2a63e7f..2f74a74 100755
--- a/fnb58_dump.sh
+++ b/fnb58_dump.sh
@@ -2,6 +2,8 @@

 # just change to your MAC....
 BT_MAC="BA:03:1C:67:56:22";
+# 98:DA:B0:01:D6:15 FNB58-047732
+BT_MAC="98:DA:B0:01:D6:15";

 OLD_IFS=$IFS;

root@rpi4:/home/pi/FNB58#

root@rpi4:/home/pi/FNB58# ./fnb58_dump.sh
connect to 98:DA:B0:01:D6:15: Function not implemented (38)
.pre
RD TC66/TC66C Type-C PD trigger USB-C Voltmeter ammeter voltage 2 way current meter multimeter PD charger battery USB Tester

https://www.aliexpress.com/item/32968303350.html

https://sigrok.org/wiki/RDTech_TC66C

https://www.youtube.com/watch?v=rOlhibDUJgs

bluetooth le range is very losy, it's about 30cm so you almost have to put Android phone on top of TC66C to make it work :-(

^ TC66C Reverse Engineering

https://ralimtek.com/reverse%20engineering/software/tc66c-reverse-engineering/

https://github.com/Ralim/TC66C

newer version: https://github.com/Ircama/TC66C

.pre
pi@rpi2 ~/TC66C $ git remote -v
origin  https://github.com/Ircama/TC66C (fetch)
origin  https://github.com/Ircama/TC66C (push)
pi@rpi2 ~/TC66C $ git branch -a
* keyboard_mgmt
  master
  remotes/origin/HEAD -> origin/master
  remotes/origin/keyboard_mgmt
  remotes/origin/master

pi@rpi2 ~/TC66C $ sudo apt install python3-curtsies

pi@rpi2 ~/TC66C $ sudo pip3 install bluepy

pi@rpi2 ~/TC66C $ sudo ./scan.py


.pre
{toc: }

https://www.pine64.org/pinephone/

https://wiki.pine64.org/index.php/PinePhone

https://wiki.pine64.org/wiki/PinePhone_v1.1_-_Braveheart

^ Full specifications

* 4 x ARM Cortex A53 cores @ 1.152 GHz
* ARM Mali 400 MP2 GPU
* 2GB / 3GB LPDDR3 RAM
* 5.95″ LCD 1440×720, 18:9 aspect ratio (hardened glass)
* Bootable Micro SD
* 16GB / 32GB eMMC
* HD digital video out
* USB Type C (Power, Data and Video Out)
* Quectel EG25-G with worldwide bands
* Built-in 802.11 b/g/n WiFi with Bluetooth: 4.0
* GNSS: GPS, GPS-A, GLONASS
* Vibration motor
* RGB status LED
* Selfie and Main camera (2/5Mpx respectively)
* Main Camera: Single OV5640, 5MP, 1/4″, LED Flash
* Selfie Camera: Single GC2035, 2MP, f/2.8, 1/5″
* Sensors: accelerator, gyro, proximity, compass, ambient light
* 3 External Switches: volume up, volume down, and power
* Hardware switches: LTE/GNSS, WiFi, Microphone, Speaker, Cameras
* Six pogo pins allowing for custom hardware extensions such as a thermal camera, wireless charging, NFC, a extended battery case, or keyboard case
* Samsung J7 form-factor 3000mAh battery
* Case is matte black finished plastic
* Headphone jack

^ postmarketos

https://wiki.postmarketos.org/wiki/PINE64_PinePhone_(pine64-pinephone)#Installation

.pre
wget https://images.postmarketos.org/bpo/v21.12/pine64-pinephone/sxmo-de-sway/20220202-0445/20220202-0445-postmarketOS-v21.12-sxmo-de-sway-1.7.0-pine64-pinephone.img.xz

dpavlin@nuc:/tmp$ xz --decompress --stdout 20220202-0445-postmarketOS-v21.12-sxmo-de-sway-1.7.0-pine64-pinephone.img.xz | \
 sudo dd of=/dev/sdc bs=4M status=progress iflag=fullblock oflag=direct conv=fsync
.pre

^ modem upgrade

https://github.com/the-modem-distro/pinephone_modem_sdk/

https://github.com/the-modem-distro/pinephone_modem_sdk/blob/kirkstone/docs/AT_INTERFACE.md

.pre
pine64-pinephone:~$ sh -x ./modem-serial.sh
+ sudo picocom --echo --omap ignlf /dev/ttyUSB2

ati

Quectel
EG25
Revision: EG25GGBR07A07M2G

OK

# battery
AT+CBC

+CBC: 0,93,4114

# versions
AT+CGMI

Quectel

AT+CGMM

EG25

AT+CGMR

EG25GGBR07A07M2G

# Get ADSP firmware version
AT+QGMR

EG25GGBR07A07M2G_01.002.01.002
.pre

https://github.com/the-modem-distro/pinephone_modem_sdk/blob/kirkstone/docs/FLASHING.md#adsp-versions

^^ upgrade modem firmware

.pre
pine64-pinephone:/home/user/modem-firmware# sh -x flashall
+ echo 'Sending AT+QFASTBOOT...'
Sending AT+QFASTBOOT...
+ sudo sh -c 'echo -ne "AT+QFASTBOOT\r" > /dev/ttyUSB2'
+ fastboot oem stay
< waiting for any device >
[Mon Jun 12 10:52:53 2023] usb 2-1: USB disconnect, device number 8
[Mon Jun 12 10:52:53 2023] option1 ttyUSB0: GSM modem (1-port) converter now disconnected from ttyUSB0
[Mon Jun 12 10:52:53 2023] option 2-1:1.0: device disconnected
[Mon Jun 12 10:52:53 2023] option1 ttyUSB1: GSM modem (1-port) converter now disconnected from ttyUSB1
[Mon Jun 12 10:52:53 2023] option 2-1:1.1: device disconnected
[Mon Jun 12 10:52:53 2023] option1 ttyUSB2: GSM modem (1-port) converter now disconnected from ttyUSB2
[Mon Jun 12 10:52:53 2023] option 2-1:1.2: device disconnected
[Mon Jun 12 10:52:53 2023] option1 ttyUSB3: GSM modem (1-port) converter now disconnected from ttyUSB3
[Mon Jun 12 10:52:53 2023] option 2-1:1.3: device disconnected
[Mon Jun 12 10:52:53 2023] qmi_wwan 2-1:1.4 wwan0: unregister 'qmi_wwan' usb-1c1b000.usb-1, WWAN/QMI device
Jun 12 10:52:54 pine64-pinephone authpriv.notice sudo:     root : TTY=pts/0 ; PWD=/home/user/modem-firmware ; USER=root ; COMMAND=/bin/sh -c echo -ne "AT+QFASTBOOT\r" > /dev/ttyUSB2
Jun 12 10:52:54 pine64-pinephone daemon.info [1966]: <info>  [base-manager] port ttyUSB0 released by device '/sys/devices/platform/soc/1c1b000.usb/usb2/2-1'
Jun 12 10:52:54 pine64-pinephone daemon.info [1966]: <info>  [base-manager] port ttyUSB1 released by device '/sys/devices/platform/soc/1c1b000.usb/usb2/2-1'
Jun 12 10:52:54 pine64-pinephone daemon.info [1966]: <info>  [base-manager] port ttyUSB2 released by device '/sys/devices/platform/soc/1c1b000.usb/usb2/2-1'
Jun 12 10:52:54 pine64-pinephone daemon.info [1966]: <info>  [base-manager] port ttyUSB3 released by device '/sys/devices/platform/soc/1c1b000.usb/usb2/2-1'
Jun 12 10:52:54 pine64-pinephone daemon.info [1966]: <info>  [base-manager] port wwan0 released by device '/sys/devices/platform/soc/1c1b000.usb/usb2/2-1'
Jun 12 10:52:54 pine64-pinephone daemon.warn [1966]: <warn>  Cannot read from istream: connection broken
Jun 12 10:52:54 pine64-pinephone daemon.info [1966]: <info>  [modem6] port 'cdc-wdm0' no longer controllable, reprobing
Jun 12 10:52:54 pine64-pinephone daemon.info NetworkManager[2272]: <info>  [1686559974.1549] device (cdc-wdm0): state change: disconnected -> unmanaged (reason 'removed', sys-iface-state: 'removed')
Jun 12 10:52:54 pine64-pinephone daemon.info [1966]: <info>  [base-manager] port cdc-wdm0 released by device '/sys/devices/platform/soc/1c1b000.usb/usb2/2-1'
[Mon Jun 12 10:52:54 2023] usb 2-1: new high-speed USB device number 9 using ehci-platform
FAILED (remote: 'unknown command')
fastboot: error: Command failed
+ fastboot flash aboot appsboot.mbn
Sending 'aboot' (279 KB)                           OKAY [  0.012s]
Writing 'aboot'                                    OKAY [  0.145s]
Finished. Total time: 0.168s
+ fastboot reboot
Rebooting                                          OKAY [  0.017s]
[Mon Jun 12 10:52:55 2023] usb 2-1: USB disconnect, device number 9
Finished. Total time: 0.067s
+ sleep 1
+ fastboot oem stay
< waiting for any device >
[Mon Jun 12 10:52:56 2023] usb 2-1: new high-speed USB device number 10 using ehci-platform
OKAY [  0.002s]
Finished. Total time: 0.002s
+ sleep 1
+ fastboot flash:raw boot boot-mdm9607.img
< waiting for any device >
Sending 'boot' (4600 KB)                           OKAY [  0.166s]
Writing 'boot'                                     OKAY [  1.753s]
Finished. Total time: 1.937s
+ fastboot flash:raw recovery boot-mdm9607.img
Sending 'recovery' (4600 KB)                       OKAY [  0.162s]
Writing 'recovery'                                 OKAY [  1.752s]
Finished. Total time: 1.932s
+ fastboot flash system rootfs-mdm9607.ubi
Sending 'system' (27648 KB)                        OKAY [  0.958s]
Writing 'system'                                   OKAY [ 11.163s]
Finished. Total time: 12.133s
+ fastboot flash recoveryfs recoveryfs.ubi
Sending 'recoveryfs' (13056 KB)                    OKAY [  0.454s]
Writing 'recoveryfs'                               OKAY [  4.686s]
Finished. Total time: 5.153s
+ fastboot reboot
Rebooting                                          OKAY [  0.004s]
[Mon Jun 12 10:53:20 2023] usb 2-1: USB disconnect, device number 10
Finished. Total time: 0.055s
+ echo 'Done!'
Done!
pine64-pinephone:/home/user/modem-firmware# [Mon Jun 12 10:53:21 2023] usb 2-1: new high-speed USB device number 11 using ehci-platform
[Mon Jun 12 10:53:26 2023] usb 2-1: USB disconnect, device number 11
[Mon Jun 12 10:53:42 2023] usb 2-1: new high-speed USB device number 12 using ehci-platform
[Mon Jun 12 10:53:42 2023] option 2-1:1.0: GSM modem (1-port) converter detected
[Mon Jun 12 10:53:42 2023] usb 2-1: GSM modem (1-port) converter now attached to ttyUSB0
[Mon Jun 12 10:53:42 2023] option 2-1:1.1: GSM modem (1-port) converter detected
[Mon Jun 12 10:53:42 2023] usb 2-1: GSM modem (1-port) converter now attached to ttyUSB1
[Mon Jun 12 10:53:42 2023] option 2-1:1.2: GSM modem (1-port) converter detected
[Mon Jun 12 10:53:42 2023] usb 2-1: GSM modem (1-port) converter now attached to ttyUSB2
[Mon Jun 12 10:53:42 2023] option 2-1:1.3: GSM modem (1-port) converter detected
[Mon Jun 12 10:53:42 2023] usb 2-1: GSM modem (1-port) converter now attached to ttyUSB3
[Mon Jun 12 10:53:42 2023] qmi_wwan 2-1:1.4: cdc-wdm0: USB WDM device
[Mon Jun 12 10:53:42 2023] qmi_wwan 2-1:1.4 wwan0: register 'qmi_wwan' at usb-1c1b000.usb-1, WWAN/QMI device, 32:5f:5b:44:e8:c1
Jun 12 10:53:43 pine64-pinephone user.notice postmarketOS:modem-setup: Modem already configured
Jun 12 10:53:54 pine64-pinephone daemon.info [1966]: <info>  [device /sys/devices/platform/soc/1c1b000.usb/usb2/2-1] creating modem with plugin 'quectel' and '6' ports
Jun 12 10:53:54 pine64-pinephone daemon.warn [1966]: <warn>  [plugin/quectel] could not grab port ttyUSB3: Cannot add port 'tty/ttyUSB3', unhandled port type
Jun 12 10:53:54 pine64-pinephone daemon.info [1966]: <info>  [base-manager] modem for device '/sys/devices/platform/soc/1c1b000.usb/usb2/2-1' successfully created
Jun 12 10:53:55 pine64-pinephone daemon.warn [1966]: <warn>  [modem7] couldn't query SIM slots: QMI protocol error (94): 'NotSupported'
Jun 12 10:53:56 pine64-pinephone daemon.warn [1966]: <warn>  [modem7/sim5] couldn't load list of emergency numbers: uninitialized emergency numbers list
Jun 12 10:53:56 pine64-pinephone daemon.warn [1966]: <warn>  [modem7] couldn't load list of own numbers: Couldn't get MSISDN: QMI protocol error (16): 'NotProvisioned'
Jun 12 10:53:56 pine64-pinephone daemon.info [1966]: <info>  [modem7] state changed (unknown -> disabled)
Jun 12 10:53:56 pine64-pinephone daemon.info NetworkManager[2272]: <info>  [1686560036.9081] manager: (cdc-wdm0): new Broadband device (/org/freedesktop/NetworkManager/Devices/10)
Jun 12 10:53:56 pine64-pinephone daemon.info NetworkManager[2272]: <info>  [1686560036.9131] device (cdc-wdm0): state change: unmanaged -> unavailable (reason 'managed', sys-iface-state: 'external')
Jun 12 10:53:56 pine64-pinephone daemon.info NetworkManager[2272]: <info>  [1686560036.9154] device (cdc-wdm0): modem state 'enabling'
Jun 12 10:53:56 pine64-pinephone daemon.info NetworkManager[2272]: <info>  [1686560036.9182] device (cdc-wdm0): state change: unavailable -> disconnected (reason 'none', sys-iface-state: 'managed')
Jun 12 10:53:56 pine64-pinephone daemon.info [1966]: <info>  [modem7] state changed (disabled -> enabling)
Jun 12 10:53:57 pine64-pinephone daemon.info [1966]: <info>  [modem7] power state updated: on
Jun 12 10:53:57 pine64-pinephone daemon.info [1966]: <info>  [modem7] state changed (enabling -> enabled)
Jun 12 10:53:57 pine64-pinephone daemon.info [1966]: <info>  [modem7] 3GPP registration state changed (unknown -> registering)
Jun 12 10:53:57 pine64-pinephone daemon.info [1966]: <info>  [modem7] 3GPP registration state changed (registering -> roaming)
Jun 12 10:53:57 pine64-pinephone daemon.info [1966]: <info>  [modem7] state changed (enabled -> registered)
Jun 12 10:54:06 pine64-pinephone daemon.warn [1966]: <warn>  [modem7] couldn't load network timezone from the current network

pine64-pinephone:/home/user/modem-firmware#
pine64-pinephone:/home/user/modem-firmware# fwupdmgr get-devices
Jun 12 10:54:17 pine64-pinephone authpriv.notice polkitd[2031]: Registered Authentication Agent for unix-process:28593:6556826 (system bus name :1.92 [/usr/bin/pkttyagent --notify-fd 6 --fallback], object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale C.UTF-8)
WARNING: UEFI capsule updates not available or enabled in firmware setup
  See https://github.com/fwupd/fwupd/wiki/PluginFlag:capsules-unsupported for more information.
WARNING: This package has not been validated, it may not work properly.
pine64 Pine64 PinePhone Braveheart (1.1)
│
├─Unknown Device:
│     Device ID:          0e0c93c8b4bb222157feedbde8f863e23bd1a8f7
│     Current version:    0x1400000000000000
│     Vendor:             EMMC:0x0000e1
│     GUID:               ba81658c-572e-5097-a08f-f9f023bb4224 ← EMMC\MAN_00E1&OEM_0116
│     Device Flags:       • Internal device
│                         • Updatable
│
└─QUECTEL Mobile Broadband Module:
      Device ID:          976c4a39e87f61e6940ea6a8d39c583cfa99615f
      Summary:            Quectel EG25-G modem
      Current version:    EG25GGBR07A07M2G_01.002.01.002
      Vendor:             Qualcomm (USB:0x2C7C, USB:0x18D1)
      GUIDs:              db379a33-254f-5140-b37e-d36ae7e5c039
                          d18f31f1-a3fa-55a2-b4ed-decfbc1e004d ← USB\VID_2C7C&PID_0125&REV_0318&NAME_EG25GGB
                          1a2996cb-f86e-5583-a464-e1b96e1c6ae9 ← USB\VID_2C7C&PID_0125&REV_0318
                          587bf468-6859-5522-93a7-6cce552a0aa3 ← USB\VID_2C7C&PID_0125
                          22ae45db-f68e-5c55-9c02-4557dca238ec ← USB\VID_2C7C
      Device Flags:       • Updatable
                          • System requires external power source
                          • Supported on remote server
                          • Device supports switching to a different branch of firmware
                          • Unsigned Payload

.pre
[FLE] wristband with heart rate monitor

nRF51822

Brand: Makibes
Model: ID107
Bluetooth version: V4.0 BLE
Waterproof rating: Life-level waterproof
Main chip: Nordic nRF51822
Pulse sensor: Silicon labs Si1142
G-sensor: kx022-1020

Android APK VeryFit 2.0: https://apkpure.com/veryfit/com.watch.life/versions

Possible free firmware for similar but newer device:

https://github.com/StarGate01/chrzwatch-firmware

Unfortunately not compatible with https://gadgetbridge.org/

.pre
root@rpi2:/home/pi# grep Wrist screenlog.0
CD:57:1B:79:77:B2 Wristband
CD:57:1B:79:77:B2 Wristband
CD:57:1B:79:77:B2 Wristband
CD:57:1B:79:77:B2 Wristband

.pre
Also known as Huawei Honor 7 Lite, Huawei GT3

but 5c doesn't have finger printer server (EU model)

{toc: }

^ specs

| Technology | GSM / HSPA / LTE |
| Launch Announced | 2016, April |
| Status | Available. Released 2016, May |
| Body Dimensions | 147.1 x 73.8 x 8.3 mm (5.79 x 2.91 x 0.33 in) |
| Weight | 156 g (5.50 oz) |
| SIM | Hybrid Dual SIM (Nano-SIM, dual stand-by) |
| Display Type | IPS LCD capacitive touchscreen, 16M colors |
| Size | 5.2 inches, 74.5 cm2 (~68.7% screen-to-body ratio) |
| Resolution | 1080 x 1920 pixels, 16:9 ratio (~424 ppi density) |
| Platform OS | Android 6.0 (Marshmallow), upgradable to 7.0 (Nougat); EMUI 4.1 |
| Chipset | HiSilicon Kirin 650 (16 nm) |
| CPU | Octa-core (4x2.0 GHz Cortex-A53 & 4x1.7 GHz Cortex-A53) |
| GPU | Mali-T830MP2 |
| Memory | Card slot microSDXC (uses shared SIM slot) |
| Internal | 16GB 2GB RAM |
| Main Camera | Single 13 MP, f/2.0, AF |
| Features | LED flash, panorama, HDR |
| Video | 1080p@30fps |
| Selfie camera | Single 8 MP, f/2.0 |
| Sound | Loudspeaker Yes |
| 3.5mm jack | Yes |
| Comms | WLAN Wi-Fi 802.11 b/g/n, hotspot |
| Bluetooth | 4.1, A2DP, LE |
| GPS | Yes, with A-GPS, GLONASS/ BDS (region dependent) |
| Radio | FM radio |
| USB | microUSB 2.0 |
| Features | Sensors Accelerometer, proximity, compass |
| Battery | Non-removable 3000 mAh battery |
| Misc | Colors Silver, Gray, Gold |
| Models | NEM-UL10, NEM-TL00H, NEM-L21, NMO-L31, NMO-L22, NMO-L23, NMO-L01, NEM-L22, NEM-L51, NEM-AL10 |
| SAR | 1.26 W/kg (head) 0.43 W/kg (body) |
| SAR EU | 1.56 W/kg (head) 1.24 W/kg (body) |
| Price | About 170 EUR |
| Tests | Performance Basemark OS II 2.0: 1221 |
| Basemark X: 7735 |
| Display | Contrast ratio: 733 (nominal), 2.506 (sunlight) |
| Camera | Photo / Video |
| Loudspeaker | Voice 66dB / Noise 71dB / Ring 74dB |
| Audio quality | Noise -90.4dB / Crosstalk -87.9dB |
| Battery life | Endurance rating 75h |

.pre
[167374.310193] usb 3-2: new high-speed USB device number 8 using ehci-pci
[167374.467237] usb 3-2: New USB device found, idVendor=12d1, idProduct=107e, bcdDevice= 2.99
[167374.467244] usb 3-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[167374.467247] usb 3-2: Product: NEM-L21
[167374.467250] usb 3-2: Manufacturer: HUAWEI
[167374.467253] usb 3-2: SerialNumber: 8SC4C17419000317
[167374.472036] usb-storage 3-2:1.1: USB Mass Storage device detected
[167374.476015] scsi host4: usb-storage 3-2:1.1
[167375.503071] scsi 4:0:0:0: CD-ROM            Linux    File-CD Gadget   0401 PQ: 0 ANSI: 2
[167375.504618] sr 4:0:0:0: Power-on or device reset occurred
[167375.511385] sr 4:0:0:0: [sr0] scsi-1 drive
[167375.513109] sr 4:0:0:0: Attached scsi CD-ROM sr0
[167375.513522] sr 4:0:0:0: Attached scsi generic sg1 type 5

.pre

but doesn't show in adb devices

.pre
Dial *#*#1357946#*#*
.pre

^ unlock bootloader

huawei doesn't provide official way to do so any more.

https://www.android-hilfe.de/forum/huawei-allgemein.467/huawei-unlock-bootloader-code-generator.756226.html

https://www.droidthunder.com/unlock-bootloader-of-huawei/

^ huawei exploit

(not for 5c, but interesting)

https://labs.taszk.io/articles/post/reunzip/
{file: inspiron-mini9_service manual_en-us.pdf}

.pre
dpavlin@mini2:~$ lscpu 
Architecture:          i686
 CPU op-mode(s):      32-bit
 Address sizes:       32 bits physical, 32 bits virtual
 Byte Order:          Little Endian
CPU(s):                2
 On-line CPU(s) list: 0,1
Vendor ID:             GenuineIntel
 Model name:          Intel(R) Atom(TM) CPU N270  @ 1.60GHz
   CPU family:        6
   Model:             28
   Thread(s) per core: 2
   Core(s) per socket: 1
   Socket(s):         1
   Stepping:          2
   CPU(s) scaling MHz: 100%
   CPU max MHz:       1600.0000
   CPU min MHz:       800.0000
   BogoMIPS:          3191.78
   Flags:             fpu vme de tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx cons
                       tant_tsc arch_perfmon pebs bts cpuid aperfmperf pni dtes64 monitor ds_cpl est tm2 ssse3 xtpr pdcm movbe lahf_lm dther
                       m
Caches (sum of all):   
 L1d:                 24 KiB (1 instance)
 L1i:                 32 KiB (1 instance)
 L2:                  512 KiB (1 instance)

dmidecode

System Information
       Manufacturer: Dell Inc.
       Product Name: Inspiron 910
       Version: A04
       Serial Number: DRRZWF1
       UUID: 20202020-2020-2020-2020-202020202020
       Wake-up Type: Power Switch
       SKU Number: Not Specified
       Family: Not Specified

.pre

^ bios cell batery

Manual claims there is battery holder for BIOS cell battery -- there isn't. You will have to have battery with spot welded wings to which you can solder original wire to change it.
Helpful notes from chat about [ULX3S]

{toc: }

^ i2c

https://gitter.im/ulx3s/Lobby?at=5dfcf29acf771f7708ff69e9

It should not be that hard. I have i2c in SaxonSoc in other projects such as https://github.com/SpinalHDL/SaxonSoc/blob/dev/hardware/scala/saxon/board/blackice/BlackiceSocArduino.scala#L25

The generated board support packages include a generated dts, but it is not used yet and the simple i2c generator that I wrote does not generate the dts.

There is a problem building SaxonSoc Linux, that some build randomly do not work. It seems to be something to do with SDRAM access.

@Dolu1990 is about to redo the SDRAM access for the Ulx3s, which should make it more reliable and faster, as he plans to support double frequency access.

There is a lot of information on the development of the u-boot version here , which might be useful to you - SpinalHDL/SaxonSoc#7

https://github.com/SpinalHDL/SaxonSoc/pull/7

I2c Linux support will also need a spinal.lib driver here - https://github.com/SpinalHDL/linux/tree/linux-5.0.y/drivers/i2c

The terasic De1Soc version of SaxonSoc Linux has a dts entry for an led for disk access - https://github.com/SpinalHDL/buildroot/blob/saxon/board/spinal/saxon_default/spinal_saxon_default_de1_soc.dts#L194

We really need a better GPIO mapping for the Ulx3s. That might involve including adding a second gpio peripheral to the hardware (gpioB) and doing a better lpf file mapping to pins. It might mean increasing the niumbers of pins that support interrupts. It would be good to include access to the buttons and switches and to make it easy to add Pmods that need interrupt support like the enc28j60 one.

^ ecp5pll

> Mario Hoffmann @hoffma_gitlab Aug 05 16:11

Hello, I wanted to have a 90 degree shifted clock. I was trying out the ecp5pll from @emard. I get it running and the clock adjustment seems to work, but somehow it does not get shifted for me. Is this currently not working with yosys and so forth, is there anything I have to take care of, or might it just be a bug on my side? Tried to search this chat a bit and just searched a bit on the internet but the things I found about it were quite old and not necessarily about my problem. Any ideas? I am using the vhdl version btw

> emard @emard Aug 05 16:59

There's some order of signals and small delays between them for dynamic shifting to work. https://github.com/emard/ulx3s-misc/blob/master/examples/sdram/memtest_mister/hdl/top/top_memtest.v#L73 here is module to control phase shifts by pressing of BTN for testing of SDRAM with variable phase shift of the clock to chip

> Mario Hoffmann @hoffma_gitlab Aug 05 17:01

alright, ill look at that. thanks

> Mario Hoffmann @hoffma_gitlab Aug 05 17:53

Oh nice it works. My thinking was just a bit wrong and there was a little bug too. Thanks

> emard @emard Aug 05 18:07

ecp5pll has possibility for fine-precision phase adjustment but this simple BTN module doesn't generate proper phaseloadreg signal https://github.com/emard/ulx3s-misc/blob/master/examples/sdram/memtest_mister/hdl/btn_ecp5pll_phase.v#L51

^ display

https://gitter.im/ulx3s/Lobby?at=5f3b7df7ee58011680b36cb0

> emard @emard Aug 18 09:06

SSD1331 96x64 is full featured OLED beautiful contrast, but currently best buy is ST7789 1.3" 240x240 LCD less contrast but more pix and less $. Do not solder directly the display. Solder female 7-pin header and plug the display. Mechanical stabilization can be 3D printed https://github.com/emard/ulx3s/tree/master/box it will "work" properly only if whole box is printed. There is no problem with heat normally to FPGA but SSD1331 with wrong software commands can become hot to fry fingers and smoke, it happened to me once, colors faded and I just replaced display. Onboard USB-SERIAL can provide 2nd JTAG channel for openocd debugger of RISCV processor it will work but it will be VERY slow (for debug single step ok, but for transferring Mbps no).

^ rtc

https://gitter.im/ulx3s/Lobby?at=5f3b86a1a8c178017657caf6

> emard @emard Aug 18 09:43

Yes for RTC I first saw it "works" but after few reboots I found out that it resets to compile time or something. Core could consult onboard RTC using i2c and then set unix time integer counter which will continue ticking afterwards. For setting RTC we have esp32 and other options. Btw import ntptime; ntptime.settime() will set ESP32 localtime() from a pool of network NTP servers and then esp32 can initialize onboard RTC here I have played with this https://github.com/emard/ulx3s-misc/tree/master/examples/rtc/micropython-mcp7940n/esp32

https://gitter.im/ulx3s/Lobby?at=5f3dbb34750a2741302ea427

> emard @emard Aug 20 01:52

@pnru_gitlab here is 8-bit master interface. I haven't tested it very simple by reading seconds and seems ok https://github.com/emard/ulx3s-misc/blob/master/examples/rtc/i2c_master/proj/hdl/i2c_master_8bit.v

https://gitter.im/ulx3s/Lobby?at=5f3e2d1c07c30d132a9c4f58

> emard @emard Aug 20 09:58

when we are at verilog, I have found on the net several i2c bidirectional bridges. Only one code worked at our board but it works only if compiled by diamond. trellis compiles but doesn't work. Can someone take a look what I have missed: bridge: https://github.com/emard/ulx3s-misc/blob/master/examples/rtc/micropython-mcp7940n/proj/hdl/i2c_bridge.v toplevel usage: https://github.com/emard/ulx3s-misc/blob/master/examples/rtc/micropython-mcp7940n/proj/top/top_i2c_bridge.v

> emard @emard Aug 20 22:04

for me it works for any gpdi_scl/sda PULLMODE=UP, DOWN, or NONE so it's not pull setting. I can prepare a bitstream and micropython to ulx3s-bin example that initializes the clock setting time from NTP

> emard @emard Aug 20 22:18

https://github.com/emard/ulx3s-bin/tree/master/esp32/micropython/rtc can you try this RTC esp32 example for NTP setting? >>> rtcdemo.mcp.time should advance seconds

> emard @emard Aug 21 00:04

RTC traffic also appears at GPDI connector (if there's i2c chip 3.3V->5V adapter soldered on board PCA9306D). Some monitors may hold i2c lines. Also gpdi connector can be used to monitor traffic if e.g. you have hdmi breakout board
If you don't have battery, RTC will keep setting until board is powered off
If you have 2 ULX3S boards and mini-display OLED/LCD, you can connect 2 ULX3S together and on one run scopeio, which will monitor the other i2c traffic
I can prepare scope stuff for such setup because scopeio is vhdl, advanced so much that ghdl won't have chance in near future to compile it

> emard @emard Aug 21 00:09

UPS but we have problem there will be 2 RTC chips colliding address :)
about i2c master 8bit. First write highest bytes 3,2,1 (order not important) and last write byte 0, this should initiate i2c transaction. byte 3=0x80 is READ, byte 3=0x00 is write
If you write 0x00 to register 0x00 (seconds) it will stop RTC. To start, it needs 0x80 written to 0x00 (MSB bit must be set) then the RTC should start "ticking"

> emard @emard Aug 21 18:14

I fixed i2c_bridge.v to work with both trellis and diamond.

> Paul Ruiz @pnru_gitlab Aug 21 23:35

Which way does the battery go? I think with the + side (cap) up and the - side (ribbed) to the PCB?
@emard: thanks for all the links, but your code already appears to work. The long one is interesting, it uses the same two level state machine idea that my non-working i2c controller uses.

> emard @emard Aug 21 23:59

Battery goes + up (larger part of battery should be in contact with metallic holder soldered) - down (smaller part of battery in contact to big circular pad on the PCB
Glad to hear good news that my code works - it hasn't been tested on real CPU but I made some BTNs toplevel and a read and write to register 0 worked

^ scopeio

https://gitter.im/ulx3s/Lobby?at=5f3c27ffa05e464346d2f6ea

> emard @emard Aug 18 21:11

@gkankanh MAX11125 is 1Msa/s total so e.g. if you use 4ch then each channel will be 0.25MSa/s per channel. For oscilloscope it, we have ready solution at hdl4fpga/ULX3S/scopeio you will see traces on monitor. For analysis, onboard USB-serial can do 3Mbps so it could be nearly useable. For faster ADC, yes 100 Mbit ethernet ETH8720 from ebay, module for 2.2$ and for example ebay's AN108 AD/DA module 32MSa/s input, 125MSa/s output https://www.ebay.com/itm/ADDA-Module-Data-Signal-Acquisition-High-speed-Directly-pluggable-connector-/253556250998 also scopeio supports it

^ how to solder headers

https://gitter.im/ulx3s/Lobby?at=5f3cd88378f4a801801336cb

> emard @emard Aug 19 09:45

To have GP/GN not be swapped from "default" design, Either solder 90° FEMALE headers on top side of board (nice for PMODs directly) or straight 0° MALE pins down on bottom side of board. PMODs can also plug to other end of flat cable and pinout will be identical as if 90° was soldered onboard.

^ nmingen

https://gitter.im/ulx3s/Lobby?at=5f3cfbce8b8d4f633effcea7

> Lawrie Griffiths @lawrie Aug 19 12:15

I am using Ubuntu 20.04, so I need to use pip3 not pip. (You can't get python2 pip on 20.04 easily).
The installation instructions for nmgen-boards says "Todo", so I installed it like the m_labs version said.
I changed the blinky example to use ULX3S_85F_Platform and ran that. It complained that tool {} was missing.
It seemed that it needed OpenFpgaLoader for upload, so I installed that, and then the blinky worked.

.pre
from nmigen import *
from nmigen_boards.ulx3s import *


class Blinky(Elaboratable):
    def elaborate(self, platform):
        led   = platform.request("led", 0)
        timer = Signal(26)

        m = Module()
        m.d.sync += timer.eq(timer + 1)
        m.d.comb += led.o.eq(timer[-1])
        return m


if __name__ == "__main__":
    platform = ULX3S_85F_Platform()
    platform.build(Blinky(), do_program=True)
.pre

https://github.com/GuzTech/ulx3s-nmigen-examples

https://github.com/greatscottgadgets/luna

^ SDRAM memtest

https://gitter.im/ulx3s/Lobby?at=5f4ea96249a1df0a12c0d83e

> Lawrie Griffiths @lawrie Sep 01 22:04

@pnru_gitlab @Dolu1990 asked these questions about using the SDRAM, which I thought you might know something about from all your recent work on SDRAM drivers:
I'm thinking about the SDRAM
currently, the soc is at 50 mhz, and the sdram run at 100 Mhz using DDR io
but maybe we should quad pump the SDRAM, and doing some bootloader calibration to ajust read delays
i'm just currently not sure what is the critical path of the SDRAM chip themself
in other words "why they are specified to X frequancy and not more"

> Dolu1990 @Dolu1990 Sep 01 22:05

Moaaaar powaaaaaaaa

> emard @emard Sep 01 22:36

oooh yeea :)) if you want to push SDRAM near the edge and give it some heat, on selected designs it can push 133MHz chips to 180-200 MHz, fmax depends on each board. 12F performs better than 85F. Here's memtest https://github.com/emard/ulx3s-misc/tree/master/examples/sdram/memtest_mister shows results on DVI monitor and with BTNs can adjust phase shift dynamically and watch for errors.

> Dolu1990 @Dolu1990 Sep 01 23:01

<3
Nice thanks :)
So this test controle the shift of the clock sent to the DRAM ?
(it doesn't use the programable input delay ?)

> emard @emard Sep 01 23:08

Yes this has a classic sdram driver that normally needs 90° phase offset to chip hardware, but as fmax is getting higher the actual phase shift which makes it really work moves. PLL is used to provide phase shift. Paul has made a better sdram driver with cool vendor-independent delay solution with a number of NOT gates.Only ns delay per NOT gate remains vendor dependent

> Dolu1990 @Dolu1990 Sep 01 23:09

ok :D

> Paul Ruiz @pnru_gitlab 00:02

@lawrie @Dolu1990 I am not sure I understand the SDRAM questions. In any case, my latest version is here: https://gitlab.com/pnru/cortex/-/blob/master/sdram.v
In particular note new lines 45-47 - I am not sure why, but this mod generally pushes Fmax up to about 200MHz (it depends a bit on the NextPNR seed).

I am not sure what you mean by "using DDR io" - does the SDRAM chip on the ULX3S support DDR? Maybe you mean by DDR that it runs at twice the speed of the CPU or that it uses burst size 2?

I don't know what the critical path in the SDRAM chip is, but I do have a hypothesis. When working with a CAS delay of 3 clocks, the data really arrives after 2 clocks plus 6-7ns (spending on the speed grade). If you clock a grade 6 chip (PC166) faster, a clock cycle will take less than 6ns and the data will only arrive after the third rising clock edge. My guess is that the 6-7ns is related to the speed of the sense amplifiers or something like that.

^ resource utilization

https://gitter.im/ulx3s/Lobby?at=5f4f8c30d4f0f55ebbf93007

> Dolu1990 @Dolu1990 Sep 02 14:12

Is somebody aware of a way to get hearchical ressource utilisation report out from yosys/next-pnr for ECP5 ?
Basicaly, trying to nail down the ressource usage

> David Shah @daveshah1 Sep 02 14:18

You can get a hierarchical report with Yosys by passing -noflatten to synth_ecp5

^ ps2 keyboard

https://gitter.im/ulx3s/Lobby?at=5f57e59c59ac794e02f71d14

> Kid CUDA @KidCUDA_gitlab Sep 08 22:12

anyone used a PS2 keyboard with ULX3S?
like a proper PS2 keyboard with the pins adapted to USB?
is a level shifter needed or is the USB port 5V-data-tolerant?
from the schematic it doesn't look 5V tolerant but I'm not sure how else it would work with just a pure PS2 adapter as suggested in the docs

> emard @emard Sep 08 22:52

@KidCUDA_gitlab US2 pins are 5V tolerant, limited by R and Zener diodes. Still some PS/2 keyboards don't accept 3.3V levels. Best is to obtain combo PS/2+USB they usually work in both modes for ULX3S
PS/2 is normally used over OTG connector for most of our retro-computing cores, apple1-2, ti99, zx, vic20, QL just to name a few

^ cortex

source: https://gitlab.com/pnru/cortex

https://gitter.im/ulx3s/Lobby?at=5f500a7eec534f584fdbeb15

> Paul Ruiz @pnru_gitlab Sep 02 23:11

    8s is super-comfortable! Btw I wonder how did cortex start, before it ever booted they need some filesystem to hold files. Is cortex filesystem mountable by modern linux? How did they made it in early times?

The Cortex was a traditional home computer with Basic in its day. Running Unix on it was my project some 6-7 years ago. It was a long journey: porting a C compiler and tool chain, building simple kernels with a linked in user program (downloaded to the H/W via something similar to S-records), etc. When the time for disk access came, I used a tool to create & manage disk images.

For the original Unix, the file system was almost the first thing that was built, after the assembler (that is how a.out got its name: assembler output). An empty disk image was written by a custom format program. Files were then loaded from paper tape. Some 1969/1970 Unix code can be found here:
https://www.tuhs.org/cgi-bin/utree.pl
In its first incarnations it was all assembler, but many of the core ideas were already there. Some more background is here:
https://www.bell-labs.com/usr/dmr/www/hist.html

> emard @emard Sep 02 23:14

Ahaaaa so unix was not all the time available on cortex hardware. Still I'd wanted to know how did you initially start with populated filesystem. Normally e.g. if we have linux on riscv, we can mount the same partition on x86 PC, copy files and and it will work on riscv, but how was this done on cortex?

So If I understood, you have a tool that from a directory creates disk image, but there's currently no support to actually mount cortex fs on linux for example. linux has some possibility to write a user-space fs driver like "fuse" but I ghess thats difficult and fragile

> Paul Ruiz @pnru_gitlab Sep 02 23:29

You can follow my journey here, in 315 commits:
https://www.jslite.net/cgi-bin/9995/timeline?n=400&y=all&v=0

I use a program ("ufs") which creates a disk image from scratch and then adds files to it. The source code is here:
https://www.jslite.net/cgi-bin/9995/dir?ci=84b2a75947eb76db&name=fsutil

Even on the mini Cortex hardware, the CF Card uses FAT formatting and has an image file on it. I make sure the image is contiguous and the boot loader lets the Unix disk driver know in which sector the image starts. This way I can simply copy disk images to the CF card without needing to use special tools.

Actually, the card also has disk images for other OS's as well - MDEX and NOS, which are somewhat similar to CP/M and MS-DOS 3 respectively.

> emard @emard Sep 02 23:44

There has been a lot of concentrated effort! The idea to use contiguous file in FAT is very good, so the CF itself can be easily written from laptop.

> Paul Ruiz @pnru_gitlab Sep 02 23:53

Thank you. The ulx3s Cortex has it even easier: because of the ESP32, now I don't even have to worry about things being contiguous and I can ftp disk images without having to handle the SD card.

> emard @emard Sep 03 00:34

yeees it was a piece of luck that for esp32 appeared good micropython support with almost all important things working and that spi-jtag adventure turned out successful. I have ulx3s with SD in a box and once inserted SD I never move out, just ftp files. Things will be even better when WROVER-E prototype starts working, 4MB RAM, 16MB FLASH no more out of memory. Bitstreams could be unzipped on-the-fly, even larger FLASH chips supported with 64K and 256K erase blocks (esp32 must buffer data size of erase block and now we are struggling with 4K buffers)

^ saxonsoc audio

https://gitter.im/ulx3s/Lobby?at=5f6482c3603d0b37f43d3ec0

> Lawrie Griffiths @lawrie Sep 18 11:49

I have a 4-cpu 85F SaxonSoc version with music, working now.

It is now inSmp/bitstreams/ulx3s_85f_blue_4core_saxonsoc.bit
I renamed images as oldimages and the new one are in Smp/images.
You need dtb, uImage and you need to untar the new rootfs.tar.
You will also need:

.pre
root@buildroot:~# cat .asoundrc
pcm.!default {
    type            plug
    slave.pcm       "softvol"   #make use of softvol
}

pcm.softvol {
    type         softvol
    slave {
        pcm         "hw:0,0"      #redirect the output to dmix (instead of "hw:0,0")
    }
    control {
           name        "PCM"       #override the PCM slider to set the softvol volume level globally
        card     0
    }
}
.pre

To play music do: mpg123 -T -f 4096 -m file.mp3.
Or to play in the background nohup mpg123 -T -f 4096 -m file.mp3 &
It is set up for a 64MB blue 85f.

https://gitter.im/ulx3s/Lobby?at=5f648d8cf51808513b4f7db5

> olu1990 @Dolu1990 Sep 18 12:35

.asoundrc isn't necessary, it just add volume controles in alsamixer app
I would suggest to not add the .asoundrc for single core versions, as it add quite a bit of overhead
the -m of mpg123 is for mono, if the mp3 bit rate isn't to high, it might be fine in stereo
(for single core)

^ saxonsoc rtc

https://gitter.im/ulx3s/Lobby?at=5f69eb5d6a6e094525ac61f5

https://gitter.im/ulx3s/Lobby?at=5f69f087e1dd7c19548aad12

> Dolu1990 @Dolu1990 Sep 22 14:39

got the rtc to start counting seconds and read it via :

.pre
i2cset -y 0 0x6F 0x00 0x80
sleep 4
i2cget -y 0 0x6F 0x00
.pre

https://gitter.im/ulx3s/Lobby?at=5f6a4562e1dd7c19548b96f0

> Lawrie Griffiths @lawrie Sep 22 20:41

.pre
oot@buildroot:~# cat date.sh 
R6=`i2cget -y 0 0x6f 0x06`
R5=`i2cget -y 0 0x6f 0x05`
R4=`i2cget -y 0 0x6f 0x04`
R2=`i2cget -y 0 0x6f 0x02`
R1=`i2cget -y 0 0x6f 0x01`

YY="${R6:2:2}"
MON="$((${R5:2:2}-20))"
DD="${R4:2:2}"
HH="${R2:2:2}"
MM="${R1:2:2}"

echo "20$YY-$MON-$DD $HH:$MM"
root@buildroot:~# ./date.sh 
2020-9-22 19:40

date -s "`./date.sh`"
.pre

https://gitter.im/ulx3s/Lobby?at=5f6a69588fe6f11963554984

> emard @emard Sep 22 23:15

.pre
#include <stdio.h>
#include <stdlib.h>

#define I2C_SLAVE 0x703
#define O_RDWR 2

int i2c_rtc;

void rtc_open(int addr)
{
  i2c_rtc = open("/dev/i2c-0", O_RDWR);
  ioctl(i2c_rtc, I2C_SLAVE, addr);
}

void rtc_read(unsigned char *buf, int reg, int n)
{
  buf[0] = reg;
  write(i2c_rtc, buf, 1);
  read(i2c_rtc, buf, n);
}

void i2cdemo(void)
{
  int i;
  unsigned char buf[7];
  // mask for BCD          SEC   MIN   HOUR  WKDAY DAY   MONTH YEAR
  unsigned char mask[7] = {0x7F, 0x7F, 0x3F, 0x07, 0x3F, 0x1F, 0xFF};

  rtc_read(buf, 0, sizeof(buf));
  for(i = sizeof(buf)-1; i >= 0; i--)
    printf(" %02x", buf[i] & mask[i]);
  printf("\n");
}

int main(int argc, char *argv[])
{
  int i;
  rtc_open(0x6F);
  for(i = 0; i < 60; i++)
  {
    i2cdemo();
    sleep(1);
  }
  return 0;
}
root@buildroot:/home/root/rtc# ./a.out 
 20 09 22 02 21 14 27
 20 09 22 02 21 14 28
 20 09 22 02 21 14 29
 20 09 22 02 21 14 30
 20 09 22 02 21 14 31
.pre

^ saxonsoc jtag

https://gitter.im/ulx3s/Lobby?at=5f78c209dfe47e4d57464c10

> Lawrie Griffiths @lawrie Oct 03 20:25

The pins to connect to are these - https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.1/hardware/synthesis/radiona/ulx3s/smp/ulx3s_v20_linux_uboot.lpf#L342-L348

> emard @emard Oct 03 20:26

I tried to upload SVF file and it works, (fast). Yes, this pins connection is important. Is there a simple JTAG openocd scan command I can test it to make sure I connected all
Some command similar to

.pre
jtag newtap lfe5 tap -expected-id 0x21111043 -irlen 8 -irmask 0xFF -ircapture 0x5
.pre

> Dolu1990 @Dolu1990 Oct 03 20:29

hoo when openocd run it scan everything

> emard @emard Oct 03 20:29

yes yes I see it on above linked script

> Dolu1990 @Dolu1990 Oct 03 20:30

i'm not sur there a command to rescan, just rerun it ^^

> emard @emard Oct 03 20:31

OK I need to make a bit on the solder and pins to board, then I will test it and when I get vexrisc scanned by openocd jtag I will put it online for remote access

> Dolu1990 @Dolu1990 Oct 03 20:31

you should get a scan like 0x10001FFF

> Lawrie Griffiths @lawrie Oct 03 20:33

@Dolu1990 Doesn't @emard need to build your version of openocd - https://github.com/SpinalHDL/openocd_riscv

> Dolu1990 @Dolu1990 Oct 03 20:34

Yes
so :
You can source the source.sh, and then do a saxon_clone; saxon_openocd
this will build it
Then modify https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.1/bsp/radiona/ulx3s/smp/openocd/usb_connect.cfg#L2 to match the jtag you have installed, and then saxon_openocd_connect

> Dolu1990 @Dolu1990 Oct 03 21:02

sudo apt-get install libtool automake libusb-1.0.0-dev texinfo libusb-dev libyaml-dev pkg-config for the full depedency on debian

> emard @emard 00:00

.pre
Escape character is '^]'.
Open On-Chip Debugger
> init 
> scan_chain
   TapName             Enabled  IdCode     Expected   IrLen IrCap IrMask
-- ------------------- -------- ---------- ---------- ----- ----- ------
 0 fpga_spinal.bridge     Y     0x10001fff 0x10001fff     4 0x01  0x0f
.pre

Got openocd to connect

https://gitter.im/ulx3s/Lobby?at=5f7c33646e0eb844696af0a2

> Lawrie Griffiths @lawrie 11:05

You then need a usb JTAG device, preferably an FT2232 one, and you connect the pins to gn0 - gn3. I have not used openocd with SaxonSoc for a while, but @Dolu1990 uses it all the time.

^ micropython socks

https://gitter.im/ulx3s/Lobby/archives/2020/10/10?at=5f820bfb07361f0cc6430489

> kost @kost Oct 10 19:31 UTC

since you guys around SaxonSoc made such a great progress. I had to do my part of the promise.
Just released socks server for micropython at https://github.com/kost/micropython-socks
that means you can tunnel any SOCKS5 connection over ESP32
since micropython does not come with NAT support, that means you can go to the internet over ESP32 using SOCKS server.
Installation is simple if you have connected ESP32 already to the internet:
You have to run this on ulx3s repl shell:

.pre
import upip
upip.install('micropython-socks')
.pre

and then you can just simply say:

.pre
import socks
socks.start()
.pre

it will start listening on 0.0.0.0:1080 for SOCKS5 connections.
Then you can simply from SaxonSoc test it with the following (or any other host):

.pre
curl --socks5 192.168.4.1:1080 http://ifconfig.co
.pre

^ nmigen - OV7670 with st7789

https://gitter.im/ulx3s/Lobby?at=5f949a4e6c8d484be2a6df34

> Lawrie Griffiths @lawrie Oct 24 23:19

@goran-mahovlic I now have a version of the OV7670 camera application working in nmigen with the st7789 display - https://github.com/lawrie/ulx3s-nmigen-examples/tree/master/ov7670

^ oberon

https://gitter.im/ulx3s/Lobby?at=5f949d40270d004bcfea9716

> Charles Perkins @charlesap Oct 24 23:31

@pnru_gitlab @emard I have created a new disk image based on the www.projectoberon.com sources, only adding some more LED output in the inner core boot process.

Here's a zip file of a disk image that you should be able to directly write to an SD card: https://github.com/io-core/io/blob/main/images/ledboot.img.zip ... this image has the Oberon partition at the correct offset but I did not bother to format the first part with a FAT partition. It boots on my ulx3s with the earlier Oberon .bit file.

.pre
Here's the meaning of the LEDs on booting:
LEDs: 7------- In BootLoad Firmware
LEDs: 7-----1- In BootLoad Firmware
LEDs: 7----2-- In BootLoad Firmware
LEDs: -------0 Control transferred to Modules
LEDs: ------1- Control transferred to Files
LEDs: -----2-- Control transferred to Kernel
LEDs: ----3--- In Kernel - Temporary Trap installed
LEDs: ---4---- In Kernel - Stack and heap origins and limits configured
LEDs: --5----- Kernel SecMap initialized, control transferred to FileDir
LEDs: -6------ Directory traversal complete
LEDs: 7------- Sectors marked, control transferred to Modules which has loaded Oberon.
LEDs: -------- Icons are defined, display subsystem initialized, ready to load System.
LEDs: --5----0 GC in the Oberon Loop
LEDs: --5---10 GC in the Oberon Loop
LEDs: --5--210 GC in the Oberon Loop
LEDs: --5-----
.pre

If there is an early trap before the system introduces a nicer printing trap the leds will fast-blink now with the trap value (0-7).
If the system gets an error trying to load modules after the boot loader successfully loads the kernel (which Oberon needs to actually display graphics and text to the screen) then this code fast-blinks bit zero.

The Oberon source code modified with the LED output is here:

https://github.com/io-orig/projectoberon/blob/main/Kernel.Mod.NL
https://github.com/io-orig/projectoberon/blob/main/FileDir.Mod.NL
https://github.com/io-orig/projectoberon/blob/main/Files.Mod.NL
https://github.com/io-orig/projectoberon/blob/main/Modules.Mod.NL
https://github.com/io-orig/projectoberon/blob/main/Oberon.Mod.NL

^ oled pins

https://gitter.im/ulx3s/Lobby?at=5fa2bcb374152347c213d4ae

> emard @emard Nov 04 11:59

@sthornington yes bitstream projects do rearrange pins. At least GND and 3.3V must match, FPGA is flexible about pins, practical is to plug display directly without wires. Original markings are for SSD1331. ST7789 7-pin is similar but I think pin has BL (backlight) function instead of CS. wifi_gpio17 refers to the same thing and also ESP32 is flexible about SPI pinout so you can match practicaly any combination.
esp32 Channels 1 or 2 itself are the same but if you mount SD card from ESP32 it will always use channel 1 so channel 2 remains free. Without SD channel 1 or 2 are for display the same.

@sthornington of course GND and VCC can't be swapped by FPGA, because OLED draws current and must connect to hard power supply, can't be powered from FPGA 16mA pins (so low power devices actually could swap even GND/VCC). new board will have 8-pin LCD header instead of 7-pin but there's really crowded with routing so additional 2 pins are nearly impossible. But if display has GND and VCC swapped, then it will fit to external connector GN/GN 0-27 so there's still a possibility to plug such display directly on board on the side

^ rtc - i2c master example

https://gitter.im/ulx3s/Lobby?at=5fa7ba79c6fe0131d4e19d31

> emard @emard Nov 08 10:29

There is example https://github.com/emard/ulx3s-misc/tree/master/examples/rtc/i2c_master/proj which makes i2c master in verilog, talks to RTC and displays time as HEX on DVI and LCD. There can't be interference with ESP32 because ESP32 is not directly connected to RTC, FPGA is between them.

^ rt2232 second channel openocd

https://gitter.im/ulx3s/Lobby?at=5fc57a82150b213e980592d8

> emard @emard 00:04

@sthornington if you have external ft2232 it is fastest and normally used as openocd jtag debugger for softcore cpus like litex or saxonsoc linux. Secondary US1 channel is possible and fully supported by openocd, but it will be unacceptably slow to transfer big files like kernel or root fs images. https://github.com/emard/ulx3s-jtagthru/blob/master/scripts/ft231x2.ocd here is some project that has openocd script to export secondard jtag channel to external pins but normally you can use it internally to soft-core too. See also the schematics for your board (v3.0.8) how FTDI is connected to FPGA

> Simon Thornington @sthornington 01:04

@emard thanks, mostly what I want to get going is an on-board scope to dump traces, is there any particular recommended F2232 interface? Does that plug into the jtag header of the below the oled one?

> emard @emard 02:56

any FT2232 breakout board or programmer is ok. It should connect to external pins GP/GN something, depends on where litex/saxonsoc expects them, usually pins 0-5 I guess. I does not plug to JTAG header, it doesn't need to program ECP5 but the CPU RISC5 done by FPGA. If you need onboard scope to display traces in realtime check hdl4fpga project, it has great scope for our boards.

^ esp32 passthrough

https://gitter.im/ulx3s/Lobby?at=601c699dd0d32d7d4fc94dfc

> liebman @liebman Feb 04 22:39

@emard this one is improved. It tristates gpio0 instead if setting it high so that it can be used elsewhere if needed. Also added an enable that can be used as a reset for the esp32.

.pre
module ulx3s_passthru (
  input  wire txd,
  output wire rxd,
  input  wire dtr,
  input  wire rts,
  input  wire esp_txd,
  output wire esp_rxd,
  output wire esp_en,
  output wire esp_io0,
  input  wire en,
);
  // TX/RX passthru
  assign rxd     = esp_txd;
  assign esp_rxd = txd;

  // Programming logic
  // SERIAL  ->  ESP32
  // DTR RTS -> EN IO0
  //  1   1     1   Z
  //  0   0     1   Z
  //  1   0     0   Z
  //  0   1     1   0
  assign esp_en  = (~dtr |  rts) & en;
  assign esp_io0 = ( dtr | ~rts) ? 1'bz : 1'b0; // we only want to drive this pin low

endmodule
.pre

can be called like

.pre
module top(
    input wire clk_25mhz,
    output wire ftdi_rxd,
    input wire ftdi_txd,
    inout wire ftdi_ndtr,
    inout wire ftdi_nrts,
    output wire wifi_rxd,
    input wire wifi_txd,
    inout wire wifi_en,
    inout wire wifi_gpio0,
    output [7:0] led,
    input  [6:0] btn,
    output wire shutdown,
);
    ulx3s_passthru passthru(.txd(ftdi_txd),
                            .rxd(ftdi_rxd),
                            .dtr(ftdi_ndtr),
                            .rts(ftdi_nrts),
                            .esp_txd(wifi_txd),
                            .esp_rxd(wifi_rxd),
                            .esp_en(wifi_en),
                            .esp_io0(wifi_gpio0),
                            .en(btn[0]),  // btn[0] will work as a reset for esp
    );

    // blinky for something to do so we know its operational
    assign led[0]   = btn[1];
    assign led[6:1] = 0;
    assign led[7]   = wifi_gpio0;
endmodule
.pre

> liebman @liebman Feb 04 23:18

thats good to know, which are the (non esp) pins that are clock capable?
(that explains why some of my tests failed)

> emard @emard Feb 04 23:19

They are mentioned on pdf schematics_v3.0.8 let me see
https://github.com/emard/ulx3s/blob/master/doc/schematics_v308.pdf page 2 GP,GN 12 are clock capable and shared with ESP32 but small design fail is those pins are on ESP32 input only. In new board v3.1.5 I tried to fix this by routing one esp32 output capable pin to FPGA clock input capable...

PCLK .. means primary clock capable pins. they are best. GR_PCLK are second best, general routed to primary clock capable

A small fix could be possible with a jumper GN11-GN12 this will connect ESP32 pin 25 GN11 which is output capable to FPGA clock input capable at GN12

^ lpf documentation

https://gitter.im/ulx3s/Lobby?at=601fa45432e01b4f717e0ebb

> Dave Anderson @danderson 09:27

Couldn't find any decent docs other than nextpnr source code and poorly explained technical notes from lattice, so I wrote https://github.com/danderson/ulxs/blob/main/lpf.md
Also comes with pointers to the Lattice tech notes that go into more detail about e.g. ECP5 configuration and I/O pin config.

^ hdmi

https://gitter.im/ulx3s/Lobby?at=6029a8349337c51bc688733e

> splinedrive @splinedrive Feb 14 23:46

Hi, I have done a hdmi reimplementation for ulx3s and blackicemx (ice40) they have the same code base. I hope you like it. I learned from other projects to take the semantic (ulx3s-examples-dvi, fpga4fun, ...) . ulx3s has DDR and SRD support and blackicemx can only DDR. I used the pmod from Luke Wren. It works only with passive resistors and works with long hdmi cables without any problems. https://github.com/splinedrive/my_hdmi_device

^ osd

https://gitter.im/ulx3s/Lobby?at=603a1016457d6b4a948f3208

> Lawrie Griffiths @lawrie 10:25

@sylefeb I am not sure that between us, @emard and I, have documented the OSD and rom loader very well. There are lots of versions of the code in different projects. This is the spi slave from my Z80 template project - https://github.com/lawrie/ulx3s_z80_template/blob/main/src/osd/spirw_slave_v.v
The rest of the code is in that osd directory.
This is a version of the micropython code that reads and writes memory and controls the cpu remotely from the esp32 - https://github.com/lawrie/ulx3s_z80_template/blob/main/esp32/spiram.py
The rest of the esp32 code including osd.py is in that directory.
Here is a youtube video that shows the osd and loader being used - https://www.youtube.com/watch?v=YE7pSuZiN9Y&t=8s
The latest version of the osd look a bit nicer.

This is my TRS 80 Model 1 implementation that has a short description on using the OSD - https://github.com/lawrie/ulx3s_z80_trs80
Perhaps @emard knows of a better description of all this.

The OSD and loader is used by many Ulx3s projects including the Apple II, C64, ZX Spectrum, Mac Plus, QL, TI-99/4A, Amiga (OSD only), Vic 20, NES, SNES, Sega Master System, Orao, etc.
This is a good video by @Speccery that shows the OSD used on the TI-99/4A - https://www.youtube.com/watch?v=zdST3wz00KU
I don't think there is a Risc-V implementation on the Ulx3s that uses the OSD yet.

> emard @emard 12:16

@sylefeb @lawrie OSD loader behaves similar as SPI RAM using 32-bit byte address. FPGA behaves as SPI slave, ESP32 as SPI master. If slave needs to initiate transfer, there is additional IRQ line. Resources at SPI address space are memory mapped, RAM to upload for CPU, reset/halt control, buttons, OSD video chars, floppy disks etc. All is very simple and protocol is not too much standardized so it can be adapted to completely unusual usage. Generally for apple2 c64 vic20 mac trs80 etc we just copy-paste the same thing

^ saxonsoc memory map

https://gitter.im/ulx3s/Lobby?at=606dcc72bc8e6f2e0d2e5be9

> Dolu1990 @Dolu1990 Apr 07 17:14

@irvise:matrix.org

    0x340000

That's the flash address. the CPU copy that part of the flash to the SDRAM at 0x80F80000 (global address). See :

    Memory copy : https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/radiona/ulx3s/smp/app/bootloaderConfig.h#L99
    source address : OPENSBI_FLASH
    destination address : OPENSBI_MEMORY

Then it does similar things with uboot but with that set of addresses : https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/radiona/ulx3s/smp/app/bootloaderConfig.h#L22

    if I generate a program that load to the address 0x380000 it should "just work"

Yes, as long you programe is complied to sit at 0x80F00000 in the global memory space

    And where can I find more info on what memory addresses are being used for MMIO

This autogenerated header file contains all the peripheral addresses :

https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/radiona/ulx3s/smp/include/soc.h#L64

    blink

See https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/software/standalone/blinkAndEcho/src/main.c
used with https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/radiona/ulx3s/smp/include/bsp.h#L15

you can compile it using the command "saxon_standalone_compile blinkAndEcho" It will sit where uboot sit (see <https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/radiona/ulx3s/smp/linker/default.ld#L1>)

^ nmigen

https://gitter.im/ulx3s/Lobby?at=608e7b59d5e2793379e961a8

> Lawrie Griffiths @lawrie May 02 12:13

I am currently working on my nmigen OV7670 camera application - https://github.com/lawrie/ulx3s-nmigen-examples/blob/master/image/camtest.py
That now displays the image on the HDMI monitor and I am starting to add image signal processing functions like brightness and color control, and simple edge detection.

The latest code that I have pushed calculates the mouse pointer (p_x, p_y) - https://github.com/lawrie/ulx3s-nmigen-examples/blob/master/image/image_stream.py

If you set the ImageStream filter switch then pixels with a red channel value less than some threshold are filtered out and the remaining pixels are displayed on the HDMI monitor as pure red. You can adjust the threshold with the up and down arrows, and a value of about 30 seems best. As the threshold is increased the picture turns black except where the laser pointer points, and the spot gets smaller as the threshold is increased. I then calculate the min and max x and y values for those red pixels, and calculate the mid points as p_x and p_y. It seems to be working.

^ saxon esp32ecp5 start

https://gitter.im/ulx3s/Lobby?at=60b93a55a10461235db71cff

> emard @emard Jun 03 22:23

I have just checked saxonsoc linux and it still works, lAN8720 ethernet (ssh) works out of the box. Tetris still compiles and works. A small hint here is the esp32 script for new esp32ecp5 to start linux

.pre
import os
from machine import SDCard, Pin
import ecp5

os.mount(SDCard(slot=3),"/sd")
# copy to root of SD card: dtb, rootfs.cpio.uboot, uImage
# flash with "False" without starting the bitstream
ecp5.flash("/sd/linux/smp/fw_jump.bin@0x340000",0x340000,False)
ecp5.flash("/sd/linux/smp/u-boot.bin@0x380000",0x380000,False)
ecp5.prog("/sd/linux/smp/ulx3s_12f_1core_saxonsoc.bit")
os.umount("/sd")
p12=Pin(12,Pin.IN)
p13=Pin(13,Pin.IN)
p14=Pin(14,Pin.IN)
p15=Pin(15,Pin.IN)
.pre

With esp32ecp5 I'd recommend micropython builds with idf3 because idf4 builds reboot ad SD card deinit (ftp> site umount)

^ dfu and openfpgaloader

https://gitter.im/ulx3s/Lobby?at=6213c5d29a09ab24f36e464d

 I suggest new passthru with DFU integrated. Get or compile latest openFPGALoader. connect to US1 and flash this first: You don't need to unzip, openfpgaloader will detect .gz and unzip on-the-fly

.pre
download https://github.com/emard/ulx3s-bin/blob/master/fpga/dfu/85f-v317/multiboot.img.gz
openFPGALoader -b ulx3s -f --unprotect-flash --file-type raw multiboot.img.gz
.pre

If you hold BTN1 or set DIP SW1 ON and plug board to US2 (optionally press BTN0 if it doesn't power up at plug) then USB DFU compatible device should be detected and you can use much faster flashing like this

.pre
openFPGALoader -b ulx3s_dfu bitstream.bit
.pre

This is for user-bitstream, if you need to reflash bootloader DFU itself from US2, hold BTN1 and BTN2 together and use DFU alternate 5 option back to ESP32: plug to US1 again and try to erase and flash ESP32

^ bootloader switches

https://gitter.im/ulx3s/Lobby?at=62370af9f43b6d783f0de7d8

> emard @emard 12:07

@NostosArch bootloader checks DIP SW1 state on power up. Switching it afterwards doesn't matter. 3 LEDs ON means it is DFU bootloader and passthru, and US2 should enumerate DFU with 3 LEDS it should be possible to flash esp32 with 3 LEDs on. 7 LEDs on means it is in passthru only (not DFU) mode. esp32 should be able to be flashed from passthru-only mode like from DFU+passthru mode. Apart from that I can either say esp32 is flashed with something difficult to get rid of or another PC and OS should be tried.

I didn't follow, but are you using linux microsoft or apple? Does ESP32 respond with ">>>" usbserial 115200 micropyhton prompt on US1?

If you upload blink, then passthru-only mode is overwritten. Still DFU+passthru mode (3 LEDs) is kept (write protected from fujprog, only openfpgaloader can overwrite bootloader). So DFU+passthru 3 LEDS should allow flashing esp32 but of course PCs and OSs compatibility and contents of esp32 already flashed may cause difficulty
^ Overview

STM32F107 RBT6 + QCA8337 AL3C based router with serial and swd headers

* https://www.st.com/en/microcontrollers/stm32f107rb.html

Mainstream Connectivity line, ARM Cortex-M3 MCU with 128 Kbytes Flash, 72 MHz CPU, Ethernet MAC, CAN and USB 2.0 OTG

^ Firmware

According to https://wiki.mikrotik.com/wiki/SwOS/RB250_RB260#Summary

new RB260GS (CSS106-5G-1S), new RB260GSP(CSS106-1G-4P-1S) supports SwOS v2.0 and newer.

Example working (as of 2018-07-06) url download links which work for CSS106-5G-1S:

https://download2.mikrotik.com/swos2/css106/swos-css1061g4p1s-2.0.bin
https://download2.mikrotik.com/swos2/css106/swos-css1061g4p1s-2.2.bin

.pre
dpavlin@lib10:/lib10/arh-hw/backup/Mikrotik-RB260GS-CSS106-5G-1S/rb260gsp$ md5sum *
bf110ca7e1cd0558cefeacd9e0b62c19  swos-css1061g4p1s-2.0.bin
a491bbf2732937839e6a8222a876cc7a  swos-css1061g4p1s-2.2.bin
f098106dfc8ac5ad0fedf0181c68d8de  swos-css1061g4p1s-2.3.bin
f4f74f697039a83baa99d37017251805  swos-css1061g4p1s-2.4.bin
90d2ec8571dd9d9aeab1bfbaaa99dea2  swos-css1061g4p1s-2.5.bin
a7f046fc8a12b5ebeb85f9a4bb0dd275  swos-css1061g4p1s-2.6.bin
a1e7adc6ad63e5560156b0f2b6f272ce  swos-css1061g4p1s-2.7.bin



.pre

https://mikrotik.com/download (SwitchOS) latest version:

https://download.mikrotik.com/swos2/css106/swos-css106-2.13.bin

^^ version

from web interface

.pre
Firmware
Current Installed Version	2.7 (built at Fri Dec 15 2017 09:42:48 GMT+0100 (CET))
Latest Available Version	2.7 (built at Fri Dec 15 2017 09:42:48 GMT+0100 (CET))
.pre

^ reset

* hold reset while poweron

SwOS v2.x - RB260GS(CSS106-5G-1S) and RB260GSP(CSS106-1G-4P-1S)

The new RB260GS(CSS106-5G-1S) and RB260GSP(CSS106-1G-4P-1S) has built-in backup SwOS firmware which can be loaded in case standard firmware breaks or upgrade fails:

    Holding Reset button for few seconds while device is booting resets configuration and loads backup firmware SwOS 2.0p.
    After loading backup firmware SwOS 2.0p it is possible to connect to 192.168.88.1 using web browser and install new SwOS firmware.

^^ default ip: 192.168.88.1

.pre
Current Installed Version	2.0p (built at Fri Oct 21 2016 10:18:39 GMT+0200 (CEST))
Latest Available Version	2.7 (built at Fri Dec 15 2017 09:42:48 GMT+0100 (CET))


.pre

After this, router knows that there is new version, but can't download it from http://upgrade.mikrotik.com/swos2/css106/swos-css106-2.7.bin

^ Linux setup

.pre
dpavlin@x230:~$ sudo ifconfig enp0s25 192.168.88.240


wget --http-user=admin --http-password='' 'http://192.168.88.1/!stats.b'


.pre

^^ find on network

https://forum.mikrotik.com/viewtopic.php?t=162881

https://wiki.mikrotik.com/wiki/MAC_access

MNDP frames

sudo apt install mactelnet-client

.pre
dpavlin@klin:~$ mndp
Searching for MikroTik routers... Abort with CTRL+C.

IP              MAC-Address       Identity (platform version hardware) uptime
192.168.88.1    c4:ad:34:47:12:91 MikroTik (MikroTik 2.7 CSS106-5G-1S)  up 113 days 4 hours
10.60.0.1       d4:ca:6d:1:4c:ed  ccr (MikroTik 6.46.6 (testing) CCR1036-8G-2S+)  up 113 days 4 hours  XYIT-4UTW bridge60/sfp2-60
.pre
https://gregdavill.github.io/OrangeCrab/

https://github.com/gregdavill/OrangeCrab

.pre
[Mon Sep 14 13:46:12 2020] usb 2-2.3: new full-speed USB device number 8 using xhci_hcd
[Mon Sep 14 13:46:12 2020] usb 2-2.3: New USB device found, idVendor=1209, idProduct=5af0, bcdDevice= 1.01
[Mon Sep 14 13:46:12 2020] usb 2-2.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[Mon Sep 14 13:46:12 2020] usb 2-2.3: Product: OrangeCrab r0.2 DFU Bootloader v3.1
[Mon Sep 14 13:46:12 2020] usb 2-2.3: Manufacturer: GsD

.pre

^ Microwatt with Linux on OrangeCrab

https://codeconstruct.com.au/docs/microwatt-orangecrab/

.pre
⦗OSS CAD Suite⦘ dpavlin@klin:/klin/FPGA/microwatt$ make microwatt.bit 2>&1 | tee ~/tmp/build1.txt

.pre
http://www.kinetic.co.uk/TrilbyAbout.php

There is https site, but it has broken css

KINETIC AVIONICS

TRILBY Rev.2.23 2015

{toc: }

^ components

from schematic {file: Trilby2V23PUBLIC.pdf}

^^ ADG918

https://www.analog.com/en/products/adg918.html

Wideband, 43 dB Isolation at 1 GHz, CMOS 1.65 V to 2.75 V, 2:1 Mux/SPDT Switches

^^ TDA18219HN

https://www.nxp.com/part/TDA18219HN#/

Silicon tuner for terrestrial and cable digital TV reception

^^ LTC2226CUH

https://eu.mouser.com/ProductDetail/Analog-Devices/LTC2226CUH

Analog to Digital Converters - ADC LTC2226 - 12-Bit, 25Msps Low Power 3V ADC

^^ LFE5U-85F-BG381

* 45F on my board

^ jumpers

J456, 1-2 IS PI 5V AND 2-3 IS USB 5V

J451 - JTAG SELECT - REMOVE LINK FOR USB
J450 - JTAG SELECT - REMOVE LINK WHEN USING LATTICE CABLE

J30 - CFG_0 - by default pull up, jumper pulls them down
J31 - CFG_1
J32 - CFG_2

J33 - PROGRAMN - reprogram FPGA

J29

1 3V3
2 TDI
3 TMS
4 TCK
5 TDO
6 GND

J26 - INSTALL TO ENABLE EEPROM WRITING

TP18 GND
TP19 GND

J458 - GPIO

from /nuc/rpi/trilby/Trilby_v_1_03_project/impl1/trilby_test_impl1.pad

| 2 | 5V | 1 | 5V |
| 4 | H18 | 3 | E12 |
| 6 | H17 | 5 | A12 |
| 8 | J17 | 7 | A13 |
| 10 | J16 | 9 | B13 |
| 12 | E19 | 11 | C13 |
| 14 | E20 | 13 | D13 |
| 16 | F19 | 15 | E13 |
| 18 | F20 | 17 | A14 |
| 20 | GND | 19 | C14 |
| 22 | RESET | 21 | D14 |
| 24 | GND | 23 | GND |

^ rpi setup

enable spi, i2c in raspi-config

.pre
pi@trilby:~/linux-gpio-pinout $ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- 44 -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
.pre

44 - example i2c device in fpga
68 - rtc

^^ rtc

.pre
root@trilby:/home/pi# echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
root@trilby:/home/pi#
[Fri Dec 24 15:02:31 2021] i2c i2c-1: new_device: Instantiated device ds1307 at 0x68
[Fri Dec 24 15:02:31 2021] rtc-ds1307 1-0068: registered as rtc0
[Fri Dec 24 15:02:31 2021] rtc-ds1307 1-0068: setting system clock to 2000-01-01T02:29:49 UTC (946693789)

root@trilby:/home/pi# hwclock -r
2021-12-24 15:02:37.028752+00:00

.pre

^^ openocd

.pre
pi@trilby:~/openocd-rpi2-stm32 $ grep -v '^#' trilby.cfg

adapter driver bcm2835gpio

bcm2835gpio_peripheral_base 0x3F000000

bcm2835gpio_speed_coeffs 146203 36

bcm2835gpio_jtag_nums 23 27 22 24

adapter speed 50
transport select jtag

pi@trilby:~/openocd-rpi2-stm32 $ openocd -f trilby.cfg
Open On-Chip Debugger 0.11.0-rc2
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
jtag
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : BCM2835 GPIO JTAG/SWD bitbang driver
Info : clock speed 50 kHz
Warn : There are no enabled taps.  AUTO PROBING MIGHT NOT WORK!!
Info : JTAG tap: auto0.tap tap/device found: 0x41112043 (mfg: 0x021 (Lattice Semi.), part: 0x1112, ver: 0x4)
Warn : AUTO auto0.tap - use "jtag newtap auto0 tap -irlen 2 -expected-id 0x41112043"
Error: IR capture error at bit 2, saw 0x3fffffffffffff05 not 0x...3
Warn : Bypassing JTAG setup events due to errors
Warn : gdb services need one or more targets defined



.pre
{toc: }

^ video

* https://www.youtube.com/watch?v=_1yrxrl61o4
* https://www.youtube.com/watch?v=kRTs6B-kEOE

^ git

.pre
dpavlin@klin:/klin/FPGA/CFU-Playground$ git remote -v
origin  https://github.com/google/CFU-Playground.git (fetch)
origin  https://github.com/google/CFU-Playground.git (push)
dpavlin@klin:/klin/FPGA/CFU-Playground$ git submodule init
dpavlin@klin:/klin/FPGA/CFU-Playground$ git submodule update
.pre

^ ulx3s board

https://github.com/litex-hub/litex-boards/blob/master/litex_boards/targets/radiona_ulx3s.py

.pre
dpavlin@klin:/klin/FPGA/CFU-Playground$ find . -name radiona_ulx3s.py
./third_party/python/litex_boards/litex_boards/targets/radiona_ulx3s.py
./third_party/python/litex_boards/litex_boards/platforms/radiona_ulx3s.py
# edit fpga settings here
dpavlin@klin:/klin/FPGA/CFU-Playground$ vi ./third_party/python/litex_boards/litex_boards/targets/radiona_ulx3s.py
.pre

modifications for 85F {file: litex-85f.diff}

^ build

you really need riscv64 toolchain from https://github.com/sifive/freedom-tools/releases/tag/v2020.04.0-Toolchain.Only

.pre
dpavlin@klin:/klin/FPGA/CFU-Playground/proj$ cat build.sh
#!/bin/sh -xe

echo https://github.com/google/CFU-Playground

export PATH=/opt/riscv64-unknown-elf-gcc-8.3.0-2020.04.1-x86_64-linux-ubuntu14/bin/:$PATH
export TARGET=radiona_ulx3s
export UART_SPEED=115200
time make prog load
.pre

^^ sumulation

.pre
dpavlin@klin:/klin/FPGA/CFU-Playground/proj/avg_pdti8$ time make PLATFORM=sim load -j 4
.pre

^^ boot over serial using network

^^^ host with ulx3s connected

root@pihdmi:/home/pi# socat /dev/ttyUSB0,b115200,raw,echo=0 TCP:10.60.0.92:2003

^^^ machine running litex

dpavlin@klin:/klin/FPGA/CFU-Playground/proj/hps_accel$ socat TCP-LISTEN:2003 PTY,link=ttyV2,raw

# re-run terminal with new virtal ttyV2

.pre
dpavlin@klin:/klin/FPGA/CFU-Playground/proj/hps_accel$ /klin/FPGA/CFU-Playground/soc/bin/litex_term --speed 115200  --serial-boot --kernel /klin/FPGA/CFU-Playground/proj/hps_accel/build/software.bin ttyV2

litex> serialboot
Booting from serial...
Press Q or ESC to abort boot completely.
sL5DdSMmkekro
[LXTERM] Received firmware download request from the device.
[LXTERM] Uploading /klin/FPGA/CFU-Playground/proj/hps_accel/build/software.bin to 0x40000000 (1313688 bytes)...
[LXTERM] Upload complete (9.9KB/s).
[LXTERM] Booting the device.
[LXTERM] Done.
Executing booted program at 0x40000000

--============= Liftoff! ===============--
Hello, World!
.pre
https://tasmota.github.io/docs/devices/Sonoff-T1/

Configuration > Configure Module > Sonoff T1 3CH

immediately after flashing Tasmota (so it won't reset when powered from adapter):

> SetOption13 1

mapping: https://github.com/arendst/Tasmota/blob/a466c5abf33386c3dda34696e11ae975c7ac6649/tasmota/tasmota_template.h#L2468

.pre
 {                     // SONOFF_T13 - Sonoff T1 3CH (ESP8285)
    GPI8_KEY1,          // GPIO00 Button 1
    GPI8_USER,          // GPIO01 Serial RXD and Optional sensor
    GPI8_USER,          // GPIO02 Optional Sensor (J3 Pin 5)
    GPI8_USER,          // GPIO03 Serial TXD and Optional sensor
    GPI8_REL3,          // GPIO04 Blue Led and Relay 3 (0 = Off, 1 = On)
    GPI8_REL2,          // GPIO05 Blue Led and Relay 2 (0 = Off, 1 = On)
                        // GPIO06 (SD_CLK   Flash)
                        // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT)
                        // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT)
    GPI8_KEY2,          // GPIO09 Button 2
    GPI8_KEY3,          // GPIO10 Button 3
                        // GPIO11 (SD_CMD   Flash)
    GPI8_REL1,          // GPIO12 Blue Led and Relay 1 (0 = Off, 1 = On)
    GPI8_LED1_INV,      // GPIO13 Blue Led (0 = On, 1 = Off) - Link and Power status
    0, 0, 0, 0
  },
.pre
https://templates.blakadder.com/gosund_SP112_v3_4.html

GPIO #	Component
GPIO00 	Led1i
GPIO01 	None
GPIO02 	Led2i
GPIO03 	None
GPIO04 	HLWBL CF1
GPIO05 	BL0937 CF
GPIO09 	None
GPIO10 	None
GPIO12 	HLWBL SELi
GPIO13 	Relay2i
GPIO14 	Relay1
GPIO15 	None
GPIO16 	None
FLAG 	Button

.pre
{"NAME":"Gosund 112v3.4","GPIO":[56,0,57,0,132,134,0,0,131,30,21,0,0],"FLAG":4,"BASE":18}
.pre

after entering into interface following config is enabled:

.pre
{"NAME":"Gosund 112v3.4","GPIO":[320,0,321,0,2656,2720,0,0,2624,257,224,0,0,4800],"FLAG":0,"BASE":18}
.pre
https://docs.ai-thinker.com/en/esp32c3

ESP32-C3_Kit
3528

ESP-C3-32S

{toc: }

^ chip_id

.pre
dpavlin@nuc:/nuc/esp32/esp-idf/examples$ /nuc/esp32/esptool/esptool.py --port /dev/ttyUSB4 chip_id
esptool.py v3.2-dev
Serial port /dev/ttyUSB4
Connecting....
Detecting chip type... ESP32-C3
Chip is ESP32-C3 (revision 3)
Features: Wi-Fi
Crystal is 40MHz
MAC: 7c:df:a1:b6:b4:94
Uploading stub...
Running stub...
Stub running...
Warning: ESP32-C3 has no Chip ID. Reading MAC instead.
MAC: 7c:df:a1:b6:b4:94
Hard resetting via RTS pin...
.pre

^ flash_id

.pre
dpavlin@nuc:/nuc/esp32/esp-idf/examples$ /nuc/esp32/esptool/esptool.py --port /dev/ttyUSB4 flash_id
esptool.py v3.2-dev
Serial port /dev/ttyUSB4
Connecting....
Detecting chip type... ESP32-C3
Chip is ESP32-C3 (revision 3)
Features: Wi-Fi
Crystal is 40MHz
MAC: 7c:df:a1:b6:b4:94
Uploading stub...
Running stub...
Stub running...
Manufacturer: 5e
Device: 6015
Detected flash size: 2MB
Hard resetting via RTS pin...
.pre

^ module info

https://docs.ai-thinker.com/_media/esp32/docs/esp-c3-32s-kit-v1.0_specification.pdf

^^ Wiring of onboard lights

IO5 is connected to RGB blue lamp beads; IO3 is connected to
RGB red lamp beads; IO4 is connected to RGB green lamp
beads; IO19 is connected to cool color lamp beads; IO18 is
connected to warm color lamp beads;(high level is valid)
{toc: }

{image: ch341a_miniprogrammer.jpg}

This is 5V device without modification! It works for me(tm) but you have been warned

http://www.eevblog.com/forum/repair/ch341a-serial-memory-programmer-power-supply-fix/

Just lift pin 28 and put some tape under it to prevent any short circuit. Then solder one wire from this pin to pin 2 of AMS1117 and also to C4. The side of the C4 to connect is the one connected to CH341A pin 9.

{file: CHM341A-3V3-fix.jpg}

^ jumper on pins

1-2 SPI flash programmer mode
2-3 TTL serial mode

supported out-of-box by flashrom, probably better option, but anyway:

https://github.com/setarcos/ch341prog

.pre
dpavlin@nuc:/nuc/ch341a$ git clone https://github.com/setarcos/ch341prog
Cloning into 'ch341prog'...
remote: Counting objects: 104, done.
remote: Total 104 (delta 0), reused 0 (delta 0), pack-reused 104
Receiving objects: 100% (104/104), 34.79 KiB | 0 bytes/s, done.
Resolving deltas: 100% (61/61), done.
Checking connectivity... done.
dpavlin@nuc:/nuc/ch341a$ cd ch341prog/
dpavlin@nuc:/nuc/ch341a/ch341prog$ make
gcc -std=gnu99 -Wall ch341a.c main.c -o ch341prog  -lusb-1.0
dpavlin@nuc:/nuc/ch341a/ch341prog$ ./ch341prog 

Usage:
 -h, --help             display this message
 -i, --info             read the chip ID info
 -e, --erase            erase the entire chip
 -l, --length <bytes>   manually set length
 -w, --write <filename> write chip with data from filename
 -r, --read <filename>  read chip and save data to filename
 -t, --turbo            increase the i2c bus speed (-tt to use much faster speed)
 -d, --double           double the spi bus speed
.pre

^ I2C in userspace

https://sourceforge.net/projects/ch341eepromtool/

.pre
dpavlin@nuc:/nuc/ch341a/ch341eepromtool_0.5$ gcc -o ch341eeprom ch341eeprom.c ch341funcs.c -lusb-1.0
dpavlin@nuc:/nuc/ch341a/ch341eepromtool_0.5$ 
dpavlin@nuc:/nuc/ch341a/ch341eepromtool_0.5$ ./ch341eeprom 
ch341eeprom - an i2c EEPROM programming tool for the WCH CH341a IC
Version 0.5 copyright (c) 2011  asbokid <ballymunboy@gmail.com>

This program comes with asbolutely no warranty; This is free software,
and you are welcome to redistribute it under certain conditions:
GNU GPL v3 License: http://www.gnu.org/licenses/gpl.html

Usage:
 -h, --help             display this text
 -v, --verbose          verbose output
 -d, --debug            debug output
 -s, --size             size of EEPROM {24c32|24c64}
 -e, --erase            erase EEPROM (fill with 0xff)
 -w, --write <filename> write EEPROM with image from filename
 -r, --read  <filename> read EEPROM and save image to filename

Example:  ch341eeprom -v -s 24c64 -w bootrom.bin
.pre

^ flashrom SPI

Not needed anymore, included in mainline flashrom

.pre
git clone https://github.com/urjaman/flashrom/
git checkout -b origin/ch341a origin/ch341a

dpavlin@nuc:/nuc/flashrom$ sudo apt-get install pciutils-dev


.pre

^ linux kernel spi module

.pre
dpavlin@nuc:/nuc$ git clone https://github.com/gschorcht/spi-ch341-usb.git
Cloning into 'spi-ch341-usb'...
remote: Counting objects: 63, done.
remote: Total 63 (delta 0), reused 0 (delta 0), pack-reused 63
Unpacking objects: 100% (63/63), done.
dpavlin@nuc:/nuc$ cd spi-ch341-usb
dpavlin@nuc:/nuc/spi-ch341-usb$ make
make -C /usr/src/linux-headers-4.14.0-3-amd64/ M=/nuc/spi-ch341-usb  modules
make[1]: Entering directory '/usr/src/linux-headers-4.14.0-3-amd64'
  CC [M]  /nuc/spi-ch341-usb/spi-ch341-usb.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /nuc/spi-ch341-usb/spi-ch341-usb.mod.o
  LD [M]  /nuc/spi-ch341-usb/spi-ch341-usb.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.14.0-3-amd64'
dpavlin@nuc:/nuc/spi-ch341-usb$ 
dpavlin@nuc:/nuc/spi-ch341-usb$ sudo make install
[sudo] password for dpavlin: 

dpavlin@nuc:/nuc/spi-ch341-usb$ sudo modprobe spi-ch341-usb

[525021.048281] spi-ch341-usb 2-2.1.4:1.0: ch341_cfg_probe: output cs0 SPI slave with cs=0
[525021.048285] spi-ch341-usb 2-2.1.4:1.0: ch341_cfg_probe: output cs1 SPI slave with cs=1
[525021.048287] spi-ch341-usb 2-2.1.4:1.0: ch341_cfg_probe: output cs2 SPI slave with cs=2
[525021.048290] spi-ch341-usb 2-2.1.4:1.0: ch341_cfg_probe: input  gpio4 gpio=0 irq=0 (hwirq)
[525021.048292] spi-ch341-usb 2-2.1.4:1.0: ch341_cfg_probe: input  gpio5 gpio=1 irq=1 
[525021.048296] spi-ch341-usb 2-2.1.4:1.0: ch341_spi_probe: SPI master connected to SPI bus 0
[525021.048426] spi-ch341-usb 2-2.1.4:1.0: ch341_spi_probe: SPI device /dev/spidev0.0 created
[525021.048516] spi-ch341-usb 2-2.1.4:1.0: ch341_spi_probe: SPI device /dev/spidev0.1 created
[525021.048596] spi-ch341-usb 2-2.1.4:1.0: ch341_spi_probe: SPI device /dev/spidev0.2 created
[525021.049147] spi-ch341-usb 2-2.1.4:1.0: ch341_usb_probe: connected
[525021.049194] usbcore: registered new interface driver spi-ch341-usb


.pre

^ linux kernel i2c module

* https://github.com/gschorcht/i2c-ch341-usb

.pre
root@nuc:/nuc# git clone https://github.com/gschorcht/i2c-ch341-usb.git
Cloning into 'i2c-ch341-usb'...
remote: Counting objects: 39, done.
remote: Total 39 (delta 0), reused 0 (delta 0), pack-reused 39
Unpacking objects: 100% (39/39), done.
root@nuc:/nuc# cd i2c-ch341-usb
root@nuc:/nuc/i2c-ch341-usb# make
make -C /usr/src/linux-headers-4.14.0-3-amd64/ M=/nuc/i2c-ch341-usb  modules
make[1]: Entering directory '/usr/src/linux-headers-4.14.0-3-amd64'
  CC [M]  /nuc/i2c-ch341-usb/i2c-ch341-usb.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /nuc/i2c-ch341-usb/i2c-ch341-usb.mod.o
  LD [M]  /nuc/i2c-ch341-usb/i2c-ch341-usb.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.14.0-3-amd64'
root@nuc:/nuc/i2c-ch341-usb# 
root@nuc:/nuc/i2c-ch341-usb# sudo make install

root@nuc:/nuc/i2c-ch341-usb# modprobe i2c-ch341-usb

[Wed Feb  7 16:37:00 2018] i2c-ch341-usb 2-2.1.4:1.0: ch341_cfg_probe: output gpio0 gpio=0 irq=0 
[Wed Feb  7 16:37:00 2018] i2c-ch341-usb 2-2.1.4:1.0: ch341_cfg_probe: output gpio1 gpio=1 irq=1 
[Wed Feb  7 16:37:00 2018] i2c-ch341-usb 2-2.1.4:1.0: ch341_cfg_probe: output gpio2 gpio=2 irq=2 
[Wed Feb  7 16:37:00 2018] i2c-ch341-usb 2-2.1.4:1.0: ch341_cfg_probe: output gpio3 gpio=3 irq=3 
[Wed Feb  7 16:37:00 2018] i2c-ch341-usb 2-2.1.4:1.0: ch341_cfg_probe: input  gpio4 gpio=4 irq=4 (hwirq)
[Wed Feb  7 16:37:00 2018] i2c-ch341-usb 2-2.1.4:1.0: ch341_cfg_probe: input  gpio5 gpio=5 irq=5 
[Wed Feb  7 16:37:00 2018] i2c-ch341-usb 2-2.1.4:1.0: ch341_cfg_probe: input  gpio6 gpio=6 irq=6 
[Wed Feb  7 16:37:00 2018] i2c-ch341-usb 2-2.1.4:1.0: ch341_cfg_probe: input  gpio7 gpio=7 irq=7 
[Wed Feb  7 16:37:00 2018] i2c-ch341-usb 2-2.1.4:1.0: ch341_i2c_probe: created i2c device /dev/i2c-8
[Wed Feb  7 16:37:00 2018] i2c-ch341-usb 2-2.1.4:1.0: ch341_i2c_set_speed: Change i2c bus speed to 100 kbps
[Wed Feb  7 16:37:00 2018] i2c-ch341-usb 2-2.1.4:1.0: ch341_usb_probe: connected
[Wed Feb  7 16:37:00 2018] usbcore: registered new interface driver i2c-ch341-usb





.pre

^ schematics and info

* http://onetransistor.blogspot.hr/2017/08/ch341a-mini-programmer-schematic.html
* http://www.zoobab.com/ch341-usb-spi-i2c-uart-isp-dongle

I added soic 8 pinout over zif socket, because position of pin 1 is not obvious (or clearly marked anywhere on top). I suggest that you fix that with silver sharpy.

{image: ch341a_miniprogrammer_schematic.png}

^ alternative schematics

https://github.com/Upcycle-Electronics/CH341A-Pro

{file: ch341Apro_schematicV01.pdf}
{toc: }

^ OpenDPS

* https://johan.kanflo.com/hacking-the-dps5005/
* https://johan.kanflo.com/opendps-design/
* https://johan.kanflo.com/upgrading-your-dps5005/

^ pinout

{image: SWO-pinout.jpg}

^ upgrade to opensource firmware

https://github.com/kanflo/opendps.git

.pre
dpavlin@nuc:/nuc$ git clone --recursive https://github.com/kanflo/opendps.git
dpavlin@nuc:/nuc$ cd opendps/
dpavlin@nuc:/nuc/opendps$ make -C libopencm3
dpavlin@nuc:/nuc/opendps$ make -C opendps

.pre

^^ st-link

connecting rst pin to unpowered st-link stops dps5005 from booting

https://johan.kanflo.com/upgrading-your-dps5005/

^^ openocd

.pre
pi@pihdmi:~ $ sudo openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg
Open On-Chip Debugger 0.10.0+dev-01489-g06c7a53f1-dirty (2020-11-14-15:21)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
WARNING: interface/stlink-v2.cfg is deprecated, please switch to interface/stlink.cfg
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : clock speed 1000 kHz
Info : STLINK V2J28S7 (API v2) VID:PID 0483:3748
Info : Target voltage: 3.273018
Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : starting gdb server for stm32f1x.cpu on 3333
Info : Listening on port 3333 for gdb connections
.pre

^^ backup few states

from another terminal

.pre
pi@pihdmi:/nuc/opendps $ ./ocd-client.py all | tee 5V-off.txt

# exit openocd, turn output on

pi@pihdmi:/nuc/opendps $ ./ocd-client.py all | tee 5V-on.txt

.pre

^^ erase

.pre
pi@pihdmi:/nuc/opendps $ telnet localhost 4444
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> reset halt
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x080010a4 msp: 0x20001ff0
> flash erase_address unlock 0x08000000 0x10000
device id = 0x10016420
flash size = 64kbytes
erased address 0x08000000 (length 65536) in 0.145284s (440.517 KiB/s)
.pre

^^ flash

.pre
pi@pihdmi:/nuc/opendps/opendps $ make flash
  FLASH   opendps_DPS5005.srec
(echo "halt; program /nuc/opendps/opendps/opendps_DPS5005.srec verify reset" | nc -4 localhost 4444 2>/dev/null) || \
        openocd -f interface/stlink-v2.cfg \
        -f target/stm32f1x.cfg \
        -c "program opendps_DPS5005.srec verify reset exit" \
        2>/dev/null
��������Open On-Chip Debugger
> halt; program /nuc/opendps/opendps/opendps_DPS5005.srec verify reset
target halted due to debug-request, current mode: Thread
xPSR: 0x61000000 pc: 0x08000bb8 msp: 0x20001fb8
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x080010a4 msp: 0x20001ff0
** Programming Started **
device id = 0x10016420
flash size = 64kbytes
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **


pi@pihdmi:/nuc/opendps/dpsboot $ make flash
  FLASH   dpsboot.srec
(echo "halt; program /nuc/opendps/dpsboot/dpsboot.srec verify reset" | nc -4 localhost 4444 2>/dev/null) || \
        openocd -f interface/stlink-v2.cfg \
        -f target/stm32f1x.cfg \
        -c "program dpsboot.srec verify reset exit" \
        2>/dev/null
��������Open On-Chip Debugger
> halt; program /nuc/opendps/dpsboot/dpsboot.srec verify reset
target halted due to debug-request, current mode: Thread
xPSR: 0x61000000 pc: 0x08000bb8 msp: 0x20001fb8
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x080010a4 msp: 0x20001ff0
** Programming Started **
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **


.pre

^^ client software

.pre
pi@pihdmi:/nuc/opendps $ pip3 install -r requirements.txt
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting crc16==0.1.1 (from -r requirements.txt (line 1))
  Downloading https://www.piwheels.org/simple/crc16/crc16-0.1.1-cp37-cp37m-linux_armv7l.whl
Requirement already satisfied: pyserial==3.4 in /usr/lib/python3/dist-packages (from -r requirements.txt (line 2)) (3.4)
Installing collected packages: crc16
Successfully installed crc16-0.1.1
pi@pihdmi:/nuc/opendps $ cd dpsctl/

pi@pihdmi:/nuc/opendps/dpsctl $ python3 ./dpsctl.py --device /dev/ttyUSB2 --ping
Error: timeout talking to device /dev/ttyUSB2.

# swap rx/tx pins

pi@pihdmi:/nuc/opendps/dpsctl $ python3 ./dpsctl.py --device /dev/ttyUSB2 --ping
Got pong from device

pi@pihdmi:/nuc/opendps/dpsctl $ python3 ./dpsctl.py --device /dev/ttyUSB2 --query
Func       : cv (on)
  voltage  : 5000
  current  : 1000
V_in       : 10.77 V
V_out      : 5.03 V
I_out      : 0.001 A
pi@pihdmi:/nuc/opendps/dpsctl $ python3 ./dpsctl.py --device /dev/ttyUSB2 -o off

pi@pihdmi:/nuc/opendps/dpsctl $ python3 ./dpsctl.py --device /dev/ttyUSB2 --query
Func       : cv (off)
  voltage  : 5000
  current  : 1000
V_in       : 10.78 V
V_out      : 1.73 V
I_out      : 0.001 A

pi@pihdmi:/nuc/opendps/dpsctl $ python3 ./dpsctl.py --device /dev/ttyUSB2 --query
Func       : cv (off)
  voltage  : 5000
  current  : 1000
V_in       : 10.78 V
V_out      : 0.01 V
I_out      : 0.000 A

.pre

^^ serial upgrade

.pre
pi@pihdmi:/nuc/opendps/dpsctl $ python3 dpsctl.py --device /dev/ttyUSB2 -U ../opendps/opendps_DPS5005.bin
Download progress: 2% Error: timeout talking to device /dev/ttyUSB2.
.pre

SEL on power-on to stay in bootloader

.pre
# it bricked my board first time I tried it
.pre

^^ esp8266

I had trouble finding toolchain which works with it, I ended up using https://github.com/pfalcon/esp-open-sdk

.pre
dpavlin@nuc:/nuc/esp8266/esp-open-sdk$ git remote -v
origin  https://github.com/pfalcon/esp-open-sdk.git (fetch)
origin  https://github.com/pfalcon/esp-open-sdk.git (push)
.pre

I also needed to replace esptool, since this machine requires python3 version of it

.pre
ln -s /nuc/esp32/esptool/esptool.py /nuc/esp8266/esp-open-sdk/xtensa-lx106-elf/bin/esptool.py
.pre

^^^ wifi config

.pre
dpavlin@nuc:/nuc/opendps$ ls -al esp8266-proxy/esp-open-rtos/include/private_ssid_config.h
-rw-r--r-- 1 dpavlin dpavlin 60 Aug  4 10:21 esp8266-proxy/esp-open-rtos/include/private_ssid_config.h
dpavlin@nuc:/nuc/opendps$ vi esp8266-proxy/esp-open-rtos/include/private_ssid_config.h
.pre

^^^ build

.pre
dpavlin@nuc:/nuc/opendps$ cd esp8266-proxy/
dpavlin@nuc:/nuc/opendps/esp8266-proxy$ cat env.sh
export EOR_ROOT=`pwd`/esp-open-rtos
export PATH=/nuc/esp8266/esp-open-sdk/xtensa-lx106-elf/bin:$PATH
dpavlin@nuc:/nuc/opendps/esp8266-proxy$ . env.sh

dpavlin@nuc:/nuc/opendps/esp8266-proxy$ make

Merged 1 ELF section
.pre

^^^ flash

.pre
dpavlin@nuc:/nuc/opendps/esp8266-proxy$ make flash
esptool.py -p /dev/ttyUSB0 --baud 115200 write_flash -fs 16m -fm qio -ff 40m \
        0x0 esp-open-rtos/bootloader/firmware_prebuilt/rboot.bin 0x1000 esp-open-rtos/bootloader/firmware_prebuilt/blank_config.bin 0x2000 ./firmware/dpsproxy.bin
WARNING: Flash size arguments in megabits like '16m' are deprecated.
Please use the equivalent size '2MB'.
Megabit arguments may be removed in a future release.
esptool.py v3.2-dev
Serial port /dev/ttyUSB0


pi@pihdmi:/nuc/opendps/esp8266-proxy $ /nuc/esp32/esptool/esptool.py --port /dev/ttyUSB3 write_flash 0x0 esp-open-rtos/bootloader/firmware_prebuilt/rboot.bin 0x1000 esp-open-rtos/bootloader/firmware_prebuilt/blank_config.bin 0x2000 ./firmware/dpsproxy.bin
esptool.py v3.2-dev
Serial port /dev/ttyUSB3
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: 5c:cf:7f:c2:6b:19
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Flash will be erased from 0x00000000 to 0x00000fff...
Flash will be erased from 0x00001000 to 0x00001fff...
Flash will be erased from 0x00002000 to 0x00043fff...
Compressed 3104 bytes to 2169...
Wrote 3104 bytes (2169 compressed) at 0x00000000 in 0.3 seconds (effective 79.1 kbit/s)...
Hash of data verified.
Compressed 2048 bytes to 23...
Wrote 2048 bytes (23 compressed) at 0x00001000 in 0.1 seconds (effective 132.3 kbit/s)...
Hash of data verified.
Compressed 268660 bytes to 195361...
Wrote 268660 bytes (195361 compressed) at 0x00002000 in 18.0 seconds (effective 119.6 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

.pre

^^^ test

reset board and verify that it's connecting to wifi

.pre
pi@rpi4:/nuc/opendps/dpsctl $ microcom -p /dev/ttyUSB0 -s 9600
connected to /dev/ttyUSB0
Escape character: Ctrl-\
Type the escape character to get to the prompt.
2dnټ�bdbz�$�`dl��x$2�+`b:`:r�pd�zt{�[�8)1J������: sta(4c:11:ae:0d:1f:ab)
add if0
scandone
add 0
aid 16
cnt

connected with dreamhouse, channel 10
dhcp client start...
ip:192.168.3.111,mask:255.255.255.0,gw:192.168.3.1
.pre

now test client

.pre
pi@rpi4:~ $ /nuc/opendps/dpsctl/dpsctl.py -S
192.168.3.111
^C

pi@rpi4:~ $ export DPSIF=192.168.3.111

pi@rpi4:~ $ /nuc/opendps/dpsctl/dpsctl.py -q
Func       : cv (off)
  voltage  : 5000
  current  : 1000
V_in       : 9.71 V
V_out      : 0.00 V
I_out      : 0.000 A
.pre

^^^ powering esp8266

3.3v voltage is available at jtag pins, but it can't supply enough current to run esp8266

There is 5v pin from buck converter on top-left pin of 2x4 pins on left side of board (when looking from back side of module)

.pre
5v gnd
 o o
 o o
 o o
 o o
.pre

{image: IMG_20210809_170438-800.jpg}

power drain from input voltage is roughly doubled when powering esp8266 from 5v rail

| input voltage | no esp8266 | with esp8266 |
| 7.68 v | 55 mA | 110 mA |
| 9v | 46 mA | 97 mA |
{file: The-Generic-STM32F103-Pinout-Diagram.pdf}

{toc: }

stm32f103 board

^ arduino boot loader

* https://github.com/rogerclarkmelbourne/Arduino_STM32/wiki/Flashing-Bootloader-for-BluePill-Boards

^ triple usb serial

^^ pill_serial

* https://satoshinm.github.io/blog/171223_stm32serial_triple_usb-to-serial_adapter_using_stm32_blue_pill.html
* https://github.com/satoshinm/pill_serial

| Function | Pin and Port |
| USART3 TX | PB10 |
| USART3 RX | PB11 |
| USART2 TX | PA2 |
| USART2 RX | PA3 |
| USART1 TX | PA9 |
| USART1 RX | PA10 |

| USART | TX pin | RX pin | special | speed | sensor | linux |
| 3 | PB10 | PB11 |  | 9600 | [MH-Z19B] | /dev/ttyACM1 |
| 2 | PA2 | PA3 |  | 9600 |  |  |
| 1 | PA9 | PA10 | BOOT=0 | 9600 |  |  |

.pre
dpavlin@nuc:/nuc/stm32/pill_serial$ cat flash.sh
sudo ../stlink/build/Release/st-flash write src/pill_serial.bin 0x08000000
.pre

lower serial speed to 9600 so we can use slow sensors on it: {file: serial-speed.diff}

^^ bluepill-serial-monster

https://github.com/r2axz/bluepill-serial-monster

^ openocd with raspberry pi

http://git.rot13.org/?p=openocd-rpi2-stm32;a=blob;f=openocd-rpi.txt

^ clones

https://github.com/thanks4opensource/buck50/issues/2

https://github.com/keirf/Greaseweazle/wiki/STM32-Fakes

.pre
dpavlin@nuc:/nuc/stm32/Greaseweazle$ wget https://github.com/keirf/Greaseweazle/releases/download/v0.22/Greaseweazle-v0.22.zip

dpavlin@nuc:/nuc/stm32/Greaseweazle$ unzip Greaseweazle-v0.22.zip Greaseweazle-v0.22/alt/Blinky_Test-v0.22.hex
Archive:  Greaseweazle-v0.22.zip
  inflating: Greaseweazle-v0.22/alt/Blinky_Test-v0.22.hex
.pre

write it to flash using openocd

.pre
> flash write_image erase /nuc/stm32/Greaseweazle/Greaseweazle-v0.22/alt/Blinky_Test-v0.22.hex 0 ihex
auto erase enabled
wrote 5120 bytes from file /nuc/stm32/Greaseweazle/Greaseweazle-v0.22/alt/Blinky_Test-v0.22.hex in 0.299529s (16.693 KiB/s)
.pre

serial output is on the programming interface at pins A9/TX and A10/RX: Not via the USB port!

.pre
pi@pihdmi:/nuc/stm32/buck50 $ microcom -p /dev/ttyUSB1
connected to /dev/ttyUSB1
Escape character: Ctrl-\
Type the escape character to get to the prompt.

** Blinky
** Blinky Test **
** Keir Fraser <keir.xen@gmail.com>
** https://github.com/keirf/Greaseweazle
Serial = ff48:0670:8967:5655:4740:6706
Flash Size  = 128kB
Device ID = 0x0000
Revision  = 0x0000
Testing I2C1... OK
Testing I2C2... OK
Testing SPI1... OK
Testing SPI2... OK
Testing TIM1... OK
Testing TIM2... OK
Testing TIM3... OK
Testing TIM4... OK
DMA Test #1... OK
DMA Test #2... OK
DMA Test #3... OK
DMA Test #4... OK
Testing 64kB Flash... OK
Enable TIM4 IRQ... .OK
Testing 20kB SRAM (endless loop)................................................................
.pre

After flashing this test, you will not be able to address blue pill using openocd.

To work-around this problem, I switched boot0 jumper, used stm32loader (after pressing reset button) to load alternative binary.
Links that I collected while trying it out...

{toc: }

If you know Croatian, start here: http://radiona.org/wiki/inventory/fabrikator_2_mini
to configure wifi and get web interface working

.pre
M550 SSID
M551 PaSsWoRd

# verify IP from ap
M552
.pre

^ tools

* https://github.com/emard/fab2mini

^ g-code

https://marlinfw.org/docs/gcode/M018.html

Disable all steppers immediately

M18

^ schematics

* board schematics https://github.com/goran-mahovlic/stm32Board/
** http://www.lemilica.com/reversing-mini-fabrikator-v2-malyan-m100-3d-printer/

^ software

.pre
dpavlin@nuc:/nuc/Fabrikator_ii_mini$ sudo apt install repetier-host


.pre
{toc: }

^ links

* http://www.esp8266.com/
* https://github.com/esp8266/esp8266-wiki/wiki
* http://www.electrodragon.com/w/Wi07c
* https://nurdspace.nl/ESP8266

* Documentation, tools, firmwares https://onedrive.live.com/?cid=C4DDF72E6EEA3826&id=C4DDF72E6EEA3826%21631

* https://github.com/esp8266/arduino
* https://github.com/igrr/esptool-ck (with reset support)

* http://tim.jagenberg.info/2015/01/18/low-power-esp8266/

{image: module_v2.png}

* all IO is 3.3V (3.6V max)
* CH_PD i chip-enable and has to be connected to VCC (3.3V)
* RST, GPIO0, GPIO2 should be pulled up to VCC for normal operation (GPIO0 at minumum!)
* GPIO0 pull to ground for firmware update
* make sure that 3.3V VCC power supply can support 300-400mA or there *WILL* be problems!

^ serial port

baud rate 115200

.pre
AT+GMR
00160901

OK

AT+RST

OK

 ets Jan  8 2013,rst cause:4, boot mode:(3,7)

wdt reset
load 0x40100000, len 24444, room 16 
tail 12
chksum 0xe0
ho 0 tail 12 room 4
load 0x3ffe8000, len 3168, room 12 
tail 4
chksum 0x93
load 0x3ffe8c60, len 4956, room 4 
tail 8
chksum 0xbd
csum 0xbd

ready

.pre

^ ESP-201

http://www.banggood.com/ESP8266-ESP-201-Remote-Serial-Port-WIFI-Transceiver-Wireless-Module-p-964288.html

{image: ESP8266-ESP-201-pin-reference-v01.png}

from http://smarpl.com/content/esp8266-esp-201-module-first-impressions

* http://jas-hacks.blogspot.com/2015/04/iot-esp8266-esp-201-cc1110-xrf.html

> One quirk with the ESP-201 is that is IO15 has to be grounded for the device to function. To flash the device IO00 has to be grounded.

.pre
AT+RST

OK

 ets Jan  8 2013,rst cause:4, boot mode:(3,7)

wdt reset
load 0x40100000, len 212, room 16 
tail 4
chksum 0x5e
load 0x3ffe8000, len 788, room 4 
tail 0
chksum 0x1c
load 0x3ffe8314, len 72, room 8 
tail 0
chksum 0x55
csum 0x55
jump to user1

.pre

modify flash for dio instead of qio: http://smarpl.com/content/esp8266-esp-201-module-freeing-gpio9-and-gpio10

^ nodemcu

* https://github.com/nodemcu/nodemcu-firmware
* https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_en

^^ esptool.py

.pre
dpavlin@x200:/rest/cvs/esptool$ git remote -v
origin  https://github.com/themadinventor/esptool (fetch)
origin  https://github.com/themadinventor/esptool (push)

dpavlin@x200:/rest/cvs/esptool$ ./esptool.py --port /dev/ttyUSB2 read_mac
Connecting...
MAC: 18:fe:34:a0:38:72
.pre

^^ flash firmware

.pre
dpavlin@blue:/opt/Espressif/esptool$ ./esptool.py read_mac
Connecting...
MAC: 18:fe:34:a0:38:72
dpavlin@blue:/opt/Espressif/esptool$ ./esptool.py --port /dev/ttyUSB0 write_flash 0x00000 ../nodemcu-firmware/pre_build/latest/nodemcu_latest.bin 
Connecting...
Erasing flash...
Writing at 0x00010800... (17 %) 
.pre

Get latest build from https://github.com/nodemcu/nodemcu-firmware/releases

.pre
dpavlin@x200:/rest/cvs/esptool$ ./esptool.py --port /dev/ttyUSB2 write_flash 0x00000 ./nodemcu_float_0.9.6-dev_20150406.bin

dpavlin@x200:/rest/cvs/esptool$ microcom -p /dev/ttyUSB2 -s 9600
connected to /dev/ttyUSB2
Escape character: Ctrl-\
Type the escape character followed by c to get to the menu or q to quit

> node.restart()

NodeMCU 0.9.6 build 20150406  powered by Lua 5.1.4
lua: cannot open init.lua
> 
.pre

^^ build from source

For latest features, you might want to rebuild software from github source

.pre
dpavlin@x200:/rest/cvs$ git clone https://github.com/pfalcon/esp-open-sdk.git

dpavlin@x200:/rest/cvs/esp-open-sdk$ export PATH=/rest/cvs/esp-open-sdk/xtensa-lx106-elf/bin:$PATH




git clone https://github.com/nodemcu/nodemcu-firmware.git
cd nodemcu-firmware

dpavlin@x200:/rest/cvs/nodemcu-firmware$ git checkout -b dev origin/dev
Branch dev set up to track remote branch dev from origin.
Switched to a new branch 'dev'


make

# check that device is in boot loader mode

dpavlin@x200:/rest/cvs/nodemcu-firmware$ ../esptool/esptool.py --port /dev/ttyUSB1 read_mac
Connecting...
MAC: 18:fe:34:99:f2:83

# flash new firmware

dpavlin@x200:/rest/cvs/nodemcu-firmware$ make flash ESPPORT=/dev/ttyUSB1
make -C ./app flash
make[1]: Entering directory '/rest/cvs/nodemcu-firmware/app'
../tools/esptool.py --port /dev/ttyUSB1 write_flash 0x00000 ../bin/0x00000.bin 0x10000 ../bin/0x10000.bin
Connecting...
Erasing flash...
Writing at 0x0000c500... (100 %)
Erasing flash...
Writing at 0x00068c00... (100 %)

Leaving...
make[1]: Leaving directory '/rest/cvs/nodemcu-firmware/app'

.pre

^^ A library for the Microchip MCP3021 A/D converter for use with the ESP8266.

https://github.com/AllAboutEE/ESP8266-MCP3021-Library

^ nodemcu-uploader

.pre
dpavlin@x200:/rest/cvs$ git clone https://github.com/kmpm/nodemcu-uploader
dpavlin@x200:/rest/cvs/nodemcu-uploader$ ./nodemcu-uploader.py --port /dev/ttyUSB2 --baud 9600 file list
Listing files
for key,value in pairs(file.list()) do print(key,value) end
> 
.pre

^ OpenOCD JTAG

https://github.com/projectgus/openocd

http://www.esp8266.com/viewtopic.php?f=9&t=1871#p11157

| JTAG Signal | ESP8266 GPIO Pin | JTAG Pin (standard 20 pin connector) |
| TMS | 14 | 7 |
| TDI | 12 | 5 |
| TCK | 13 | 9 |
| TDO | 15 | 13 |
| RST | RST | 15 |

verified on https://visualgdb.com/tutorials/esp8266/nodemcu/jtag/

^ ESP8266 as wireless JTAG Programmer

https://github.com/emard/wifi_jtag

^ WIFI

* https://github.com/kripthor/WiFiBeaconJam

^ software serial

* C library https://github.com/plieningerweb/esp8266-software-uart
* Arduino https://github.com/plerup/espsoftwareserial

^ Sonoff

https://www.itead.cc/sonoff-wifi-wireless-switch.html
http://wiki.iteadstudio.com/Sonoff
https://github.com/arendst/Sonoff-MQTT-OTA

^^ pinout

My sonoff is early model, with just 4 pins (instead of 5)

1 - VCC
2 - RX
3 - TX
4 - GND

^ Programming

* https://tech.scargill.net/a-flashing-esp-chips-surprise/

use *dio* not *qio* to fix checksum errors

^^ CH340 USB to ESP8266 ESP-01 Wifi Module Adapter

It doesn't have GPIO0 connected to ground, so flashing doesn't work!

http://www.esp8266.com/wiki/doku.php?id=all-in-one-esp-usb-converter

^ ESP-01S DHT11 board

* https://github.com/IOT-MCU/ESP-01S-DHT11-v1.0

.pre
#define DHTTYPE DHT11
#define DHTPIN  2
DHT dht(DHTPIN, DHTTYPE, 11);
.pre

^^ adding IR led

Button is connected to RST, and if you want to add IR led (with transistor and resistor) it seems that only
way to make it work is to connect it to RX pin (gpio3). For more info see my blog post: https://blog.rot13.org/2019/08/emulate-ir-remote-for-tv-or-hvac-from-command-line-using-tasmota.html

^ KEYESTUDIO ESP8266 ESP-12F CH340G WiFi Module Board for Arduino NodeMcu

https://www.keyestudio.com/products/new-keyeastudio-nodemcu-lua-esp8266-esp-12f-wifi-module-1m-usb-cable-development-board-compatible-with-networking

{image: keyes-esp8266-pinout.jpg}
{toc: }

^ esptool and raspberry pi

I found out that older versions of esptool (like the ones deliveved by debian packages) don't work well on raspberry pi 2 and raspberry pi 4

.pre
root@pihdmi:/home/pi/linux-gpio-pinout# esptool -p /dev/ttyUSB0 read_mac
esptool.py v2.5.1
Serial port /dev/ttyUSB0
Connecting........_____....._____....._____....._____....._____....._____....._____

A fatal error occurred: Failed to connect to Espressif device: Timed out waiting for packet header

root@pihdmi:/home/pi/linux-gpio-pinout# /nuc/esp32/esptool/esptool.py --port /dev/ttyUSB0 read_mac
esptool.py v3.2-dev
Serial port /dev/ttyUSB0
Connecting........_____....._____.....___
Detecting chip type... ESP32
Chip is ESP32-D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: a4:cf:12:55:c5:60
Uploading stub...
Running stub...
Stub running...
MAC: a4:cf:12:55:c5:60
Hard resetting via RTS pin...
.pre

^ esp-idf version

.pre
dpavlin@nuc:/nuc/esp32/esp-idf$ git remote -v
origin  https://github.com/espressif/esp-idf.git (fetch)
origin  https://github.com/espressif/esp-idf.git (push)

dpavlin@nuc:/nuc/esp32/esp-idf$ git checkout -b v3.3-upy 9e70825d1e1cbf7988cf36981774300066580ea7
dpavlin@nuc:/nuc/esp32/esp-idf$ git submodule update --init --recursive
.pre

For latest micropython v4.3 leaves too little memory available for esp32ecp/ecp5

^^ v4.2.2

( 'gc', gc.isenabled(), 'alloc', gc.mem_alloc(), 'free', gc.mem_free() )
gc True alloc 25632 free 85536

enough memory, but 50% packet loss for ping to remote ppp ip

^^ v4.1.1 doesn't have ip_napt_enable

test alternative lwip lib

.pre
dpavlin@fpga:/esp32/esp-idf/components/lwip$ mv lwip lwip.old

dpavlin@fpga:/esp32/esp-idf/components/lwip$ git clone https://github.com/martin-ger/esp-lwip lwip
Cloning into 'lwip'...
remote: Enumerating objects: 49642, done.
remote: Total 49642 (delta 0), reused 0 (delta 0), pack-reused 49642
Receiving objects: 100% (49642/49642), 9.70 MiB | 14.52 MiB/s, done.
Resolving deltas: 100% (37485/37485), done.

.pre

it does work, but slowly:

.pre
dpavlin@nuc:/tmp/esp-lwip$ iperf3 -c 10.0.5.2
Connecting to host 10.0.5.2, port 5201
[  5] local 192.168.3.40 port 52086 connected to 10.0.5.2 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec   102 KBytes   833 Kbits/sec    1   28.3 KBytes
[  5]   1.00-2.00   sec  0.00 Bytes  0.00 bits/sec   10   14.1 KBytes
[  5]   2.00-3.00   sec  82.0 KBytes   673 Kbits/sec    2   22.6 KBytes
[  5]   3.00-4.00   sec  0.00 Bytes  0.00 bits/sec    0   28.3 KBytes
[  5]   4.00-5.00   sec  0.00 Bytes  0.00 bits/sec    4   19.8 KBytes
[  5]   5.00-6.00   sec  93.3 KBytes   765 Kbits/sec    4   18.4 KBytes
[  5]   6.00-7.00   sec  0.00 Bytes  0.00 bits/sec    3   5.66 KBytes
[  5]   7.00-8.00   sec  0.00 Bytes  0.00 bits/sec    0   15.6 KBytes
[  5]   8.00-9.00   sec  63.6 KBytes   522 Kbits/sec    0   15.6 KBytes
[  5]   9.00-10.00  sec  0.00 Bytes  0.00 bits/sec    2   5.66 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec   341 KBytes   279 Kbits/sec   26             sender
[  5]   0.00-10.18  sec   216 KBytes   174 Kbits/sec                  receiver

.pre

^ enviroment

.pre
dpavlin@nuc:/nuc/upy/micropython/ports/esp32$ cat env.sh
export PATH=/nuc/esp32/xtensa-esp32-elf/bin/:$PATH
export ESPIDF=/nuc/esp32/esp-idf/
.pre

^ IP_FORWARD enable in lwip

.pre
dpavlin@nuc:/nuc/upy/micropython/ports/esp32$ git diff
diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile
index 756bc8f89..aa03a6370 100644
--- a/ports/esp32/Makefile
+++ b/ports/esp32/Makefile
@@ -494,7 +494,7 @@ ESPIDF_SPI_FLASH_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/spi_flash/*.c))

 ESPIDF_ULP_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/ulp/*.c))

-$(BUILD)/$(ESPCOMP)/lwip/%.o: CFLAGS += -Wno-address -Wno-unused-variable -Wno-unused-but-set-variable
+$(BUILD)/$(ESPCOMP)/lwip/%.o: CFLAGS += -Wno-address -Wno-unused-variable -Wno-unused-but-set-variable -DIP_FORWARD=1
 ESPIDF_LWIP_O = $(patsubst %.c,%.o,\
        $(wildcard $(ESPCOMP)/lwip/apps/dhcpserver/*.c) \
        $(wildcard $(ESPCOMP)/lwip/lwip/src/api/*.c) \
.pre

^ build

.pre
dpavlin@nuc:/nuc/upy/micropython/ports/esp32$ make V=1

...

xtensa-esp32-elf-size build-GENERIC/application.elf
   text    data     bss     dec     hex filename
1100148  275360   37372 1412880  158f10 build-GENERIC/application.elf
Create build-GENERIC/application.bin
/nuc/esp32/esp-idf//components/esptool_py/esptool/esptool.py --chip esp32 elf2image --flash_mode dio --flash_freq 40m --flash_size 4MB build-GENERIC/application.elf
esptool.py v2.8
Create build-GENERIC/firmware.bin
python3 makeimg.py build-GENERIC/bootloader.bin build-GENERIC/partitions.bin build-GENERIC/application.bin build-GENERIC/firmware.bin
bootloader     21360
partitions      3072
application  1375648
total        1441184
.pre

^ deploy to esp32 using esptool ttyUSB4

.pre
dpavlin@nuc:/nuc/upy/micropython/ports/esp32$ make V=1 PORT=/dev/ttyUSB4  deploy
Building with ESP IDF v3
python3 ../../py/makeversionhdr.py build-GENERIC/genhdr/mpversion.h
python3 ../../tools/makemanifest.py -o build-GENERIC/frozen_content.c -v "MPY_DIR=../.." -v "MPY_LIB_DIR=../../../micropython-lib" -v "PORT_DIR=/nuc/upy/micropython/ports/esp32" -v "BOARD_DIR=boards/GENERIC" -b "build-GENERIC" -f"-march=xtensawin" boards/manifest.py
Writing build-GENERIC/firmware.bin to the board
/nuc/esp32/esp-idf//components/esptool_py/esptool/esptool.py --chip esp32 --port /dev/ttyUSB4 --baud 460800 write_flash -z --flash_mode dio --flash_freq 40m 0x1000 build-GENERIC/firmware.bin
esptool.py v2.8
Serial port /dev/ttyUSB4
Connecting........_____....._____....._____...
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: 24:0a:c4:31:d6:38
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 1437088 bytes to 921637...
Wrote 1437088 bytes (921637 compressed) at 0x00001000 in 21.5 seconds (effective 535.8 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...
.pre

^ serial

.pre
dpavlin@nuc:/nuc/upy/micropython/ports/esp32$ microcom -p /dev/ttyUSB4
connected to /dev/ttyUSB4
Escape character: Ctrl-\
Type the escape character to get to the prompt.

>>>
MPY: soft reboot
AP config:  ('192.168.4.1', '255.255.255.0', '192.168.4.1', '0.0.0.0')
network config: ('192.168.3.208', '255.255.255.0', '192.168.3.1', '192.168.3.1')
FTP server started on 192.168.4.1:21
FTP server started on 192.168.3.208:21
 esp32 mac: 24:0a:c4:31:d6:38 esp32upy
MicroPython v1.14-dirty on 2021-07-25; ESP32 module with ESP32
Type "help()" for more information.
>>> import machine
>>> machine.reset()
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:4972
load:0x40078000,len:10600
load:0x40080400,len:5684
entry 0x400806bc
AP config:  ('192.168.4.1', '255.255.255.0', '192.168.4.1', '0.0.0.0')
network config: ('192.168.3.208', '255.255.255.0', '192.168.3.1', '192.168.3.1')
FTP server started on 192.168.4.1:21
FTP server started on 192.168.3.208:21
 esp32 mac: 24:0a:c4:31:d6:38 esp32upy
MicroPython v1.14-dirty on 2021-07-25; ESP32 module with ESP32
Type "help()" for more information.
.pre

^ webrepl

* https://github.com/Hermann-SW/webrepl/blob/master/webrepl_client.py -- provide python repl without using usb serial port
* https://github.com/kost/webrepl-python

^ [ulx3s] ppp

* https://github.com/emard/esp32ppp
* https://github.com/micropython/micropython/issues/5369
{toc: }

bigclive https://youtu.be/_zTqZ1edrsU

https://ellestfun.en.alibaba.com/product/60341087076-801987474/IONCARE_wholesale_top_selling_Clenaer_Deodorizer_refrigerator_aroma_diffuser.html

^ Technical Specifications:

1.Ozone concentration: About 4.0ppm in “High” mode (operates 30 minutes inside a 40L closed container)

2.Effective Range:“High” mode <250L “Low” mode <150L

3.Rating Voltage: DC4.5V

4.Power Supply: 3pcs 1.5V AA-size alkaline batteries

5.Power consumption: 0.5 watts

I measured:

3.7 V * 0.029 A = 0.107 W
4 V * 0.032 A = 0.128W

This is all below 4.5V, but is test for single 18650 cell.

6.Dimensions: H116 x D80 mm

7.Weight: 0.15kg

^ INCARE GH2128

MONIC FRESHENER & DEODORIZER FOR REFRIGERATORS, CLOSETS BATHROOMS

Instructions

^^ FUNCTIONS AND FEATURES

An innovative device utilizes ionic technology to generate ozone (O₂) & anions to purify the air thoroughly.

1. Neutralize stale and foul odors with fresh air inside refrigerators, closets, bathrooms and cars, etc.

2. Kill all kinds of bacteria to avoid the growth of mildew. 3. Very ideal for use in refrigerator to keep the foods fresh for longer time.

4. Built-in micro CPU intelligently controls the operation cycle & mode by one touch and indicates with the colored LED.

5. Operated by 3 AA batteries. Low voltage indicator reminds you of replacing batteries.

^^ HOW TO OPERATE

1. Remove the battery door on the bottom of the unit, install 3 pieces "AA" 1.5V high-quality alkaline batteries (purchase separately) according to the proper polarity, close with the battery door.

2. Press the "ON/OFF" button once and the power indicator lights up. You may feel a slight breeze from the top grilles, which means the machine on working.

3. Press the "ON/OFF" button again to turn off the unit.

4. Operating mode settings:

1) When the machine is turned on, press the "MODE" button to toggle the operating modes between HIGH and LOW.

2) When the HIGH mode is selected, the power indicator will light up in green and blink.

The machine firstly performs a continuous working for about 30 minutes,
and the power indicator will blink every 2 seconds.

Then the machine will go into a cycle of automatic I-minute's sterilization and deodorization in every 1 hour,
in the other time, the machine will go to sleep and the power indicator will blink every 10 seconds.

3) When the LOW mode is selected, the power indicator will light up in orange and blink.

The machine firstly performs a continuous working for about 20 minutes,
and the power indicator will blink every 2 seconds.

Then the machine will go into a cycle of automatic 40-seconds
sterization and deodorization in every 1 hour
in the other time the machine will go to sleep and the power indicator will blink every 10 seconds.

5. When the power indicator becomes red, this is the butto voltage indicator reminds you of replacing bateries.

^^ SPECIAL ATTENTION

When the machine used in the refrigerator.

1. Make sure to place it into the refrigerator companimens ofer than the freezing compartment.

2. Before taking it from the refrigerator, make sure to tum of is power first.

Due to the lower temperature of the refingerator when the machine comes in contact with the outside air
there will be water condensation on its body and inside, if the machine keeps working,
it maybe leads to the short circuit of the electic parts and corrode the metal parts even the batteries

3. When the indicator becomes red, it's time to change the betteries

Take the machine from the refrigerator, and then wrap it with a clean plastic bag.

Before replacing with the new batteries make sure the temperature of the machine casing raises to room temperature.

^^ CAUTION

1. Take out the batteries if leaving the unit idle for a long time.

2. Do not operate the unit in areas where flammable or combusite products or vapors may be present.

3. Keep the unit away from water.

4. Do not strongly shock the unit to avoid any stack of the inter parts of the unit.

Read and save these instructions
{toc]

^ JLCPCB

* https://github.com/wokwi/kicad-jlcpcb-bom-plugin
* https://github.com/yaqwsx/jlcparts

^ Videos

^^ CEP014 - Moving to KiCad V6 with Jon Evans

https://youtu.be/dfAkYMuyhFA
{file: RC-Power_BC6_Charger.pdf}

{toc: }

^ MCU

Nuvoton M0517LBN ARM Cortex M0

Nuvoton don’t guarantee the deviation of HIRC(22.1184MHz) for M0517.
M0517 is a special part number of M051 series.

^ Open source firmware

* https://github.com/stawel/cheali-charger
* https://groups.google.com/forum/#!forum/cheali-charger
* http://www.rcgroups.com/forums/showthread.php?t=1951734

^^ Flashing

https://groups.google.com/forum/#!msg/cheali-charger/2Rz-dtwZ5Is/zUGr3PzX9bcJ

pinout:

.pre
CHARGER -------------DONGLE
ICE_DATA <--------->    SWDIO
ICE_CLK  <--------->    SWCLK
ICE_RST  <--------->    RST (on SWIM header on my programmer)
GND      <--------->    GND
VCC      <--------->     5V
.pre

{image: isp_imaxB6_M0517.jpeg}

.pre
dpavlin@x200:/rest/cvs/cheali-charger$ cat .gitmodules 
[submodule "utils/M0517_flash_tools"]
        path = utils/M0517_flash_tools
        url = https://github.com/sasam/M0517_flash_tools.git


dpavlin@x200:/rest/cvs/cheali-charger/utils/M0517_flash_tools/tcl$ openocd \
 -f /usr/share/openocd/scripts/interface/stlink-v2.cfg \
 -f target_MO517_linux.cfg \
 -f M0517_flash.tcl -f M0517_unlock.tcl
.pre

If you get following error:

.pre
Error: init mode failed (unable to connect to the target)
.pre

Connect RST pin to GND while plugging in ST-Link v2 into computer. This will start M0517 in reset mode (you might see squares in first line of display).

Then, unplug RST pin from GND and connect it to RST and restart openocd. Your IMAX B6 is probably protected, so follow instructions below to unlock it.

Open telnet connection to openocd in other terminal:

.pre
dpavlin@x200:/rest/cvs/cheali-charger$ telnet localhost 4444
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> FlashAprom /rest/cvs/cheali-charger/hex/unstable/cheali-charger-imaxB6-clone_1.99-20150727_nuvoton-M0517.hex
.pre

Output from openocd after successful flash:

.pre
Open On-Chip Debugger 0.9.0 (2015-05-28-17:08)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
Info : The selected transport took over low-level target control.
  The results might differ compared to plain JTAG/SWD
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
FlashAprom
EraseChip
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : clock speed 950 kHz
Info : STLINK v2 JTAG v23 API v2 SWIM v4 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 3.339130
Info : M0517.cpu: hardware has 4 breakpoints, 2 watchpoints
Info : accepting 'telnet' connection on tcp/4444
Image: /rest/cvs/cheali-charger/./src/hardware/nuvoton-M0517/targets/imaxB6-clone/cheali-charger-imaxB6-clone_1.00-20150617_nuvoton-M0517.bin; Size=34840; Sectors:69; FlashProces:(34840;3584,9;2584,1)
>>>>     Load FlashPgm to SRAM: NU_M051x.bin => 0x20000000
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0xc1000000 pc: 0xfffffffe msp: 0xfffffffc
276 bytes written at address 0x20000000
downloaded 276 bytes in 0.008215s (32.810 KiB/s)
>>>>     FlashInit:
sp (/32): 0x20001000
pc (/32): 0x20000000
Error: timed out while waiting for target halted

Flash is locked!
Chip erase...
.
.
.
.
.
APROM: Erased!: (0x00000000):0xFFFFFFFF
LDROM: Erased!: (0x00100000):0xFFFFFFFF
Config: Erased!: (0x0030000):0xFFFFFFFF
Image: /rest/cvs/cheali-charger/./src/hardware/nuvoton-M0517/targets/imaxB6-clone/cheali-charger-imaxB6-clone_1.00-20150617_nuvoton-M0517.bin; Size=34840; Sectors:69; FlashProces:(34840;3584,9;2584,1)
>>>>     Load FlashPgm to SRAM: NU_M051x.bin => 0x20000000
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0xc1000000 pc: 0xfffffffe msp: 0xfffffffc
276 bytes written at address 0x20000000
downloaded 276 bytes in 0.008211s (32.826 KiB/s)
>>>>     FlashInit:
sp (/32): 0x20001000
pc (/32): 0x20000000
target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x41000000 pc: 0x20000048 msp: 0x20001000
r0 (/32): 0x00000000
>>>>     FlashInit stop:
>>>>     EreaseFlash: start
     FLASH sector addr: 0x00000000
     sectors to erease: 0x00000045
r0 (/32): 0x00000000
r1 (/32): 0x00000045
sp (/32): 0x20001000
pc (/32): 0x20000058
target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x200000a2 msp: 0x20000fec
r0 (/32): 0x00000000
>>>>    FlashErease: stop
>>>>   FLASH image: /rest/cvs/cheali-charger/./src/hardware/nuvoton-M0517/targets/imaxB6-clone/cheali-charger-imaxB6-clone_1.00-20150617_nuvoton-M0517.bin to 0x00000000
>> Flash Sector: 0-6 => 0x00000000 (3584)
     SRAM load : tmp/fl.00 => 0x20000120
     FLASH addr: reg r0 0x00000000
     SIZE  addr: reg r1 0x00000e00
     BUFFR addr: reg r2 0x20000120
3584 bytes written at address 0x20000120
downloaded 3584 bytes in 0.069231s (50.555 KiB/s)
r0 (/32): 0x00000000
r1 (/32): 0x00000E00
r2 (/32): 0x20000120
sp (/32): 0x20001000
pc (/32): 0x200000AE
target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
r0 (/32): 0x00000000
>> Flash Sector: 7-13 => 0x00000e00 (3584)
     SRAM load : tmp/fl.01 => 0x20000120
     FLASH addr: reg r0 0x00000e00
     SIZE  addr: reg r1 0x00000e00
     BUFFR addr: reg r2 0x20000120
3584 bytes written at address 0x20000120
downloaded 3584 bytes in 0.068563s (51.048 KiB/s)
r0 (/32): 0x00000E00
r1 (/32): 0x00000E00
r2 (/32): 0x20000120
sp (/32): 0x20001000
pc (/32): 0x200000AE
target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
r0 (/32): 0x00000000
>> Flash Sector: 14-20 => 0x00001c00 (3584)
     SRAM load : tmp/fl.02 => 0x20000120
     FLASH addr: reg r0 0x00001c00
     SIZE  addr: reg r1 0x00000e00
     BUFFR addr: reg r2 0x20000120
3584 bytes written at address 0x20000120
downloaded 3584 bytes in 0.068231s (51.296 KiB/s)
r0 (/32): 0x00001C00
r1 (/32): 0x00000E00
r2 (/32): 0x20000120
sp (/32): 0x20001000
pc (/32): 0x200000AE
target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
r0 (/32): 0x00000000
>> Flash Sector: 21-27 => 0x00002a00 (3584)
     SRAM load : tmp/fl.03 => 0x20000120
     FLASH addr: reg r0 0x00002a00
     SIZE  addr: reg r1 0x00000e00
     BUFFR addr: reg r2 0x20000120
3584 bytes written at address 0x20000120
downloaded 3584 bytes in 0.069227s (50.558 KiB/s)
r0 (/32): 0x00002A00
r1 (/32): 0x00000E00
r2 (/32): 0x20000120
sp (/32): 0x20001000
pc (/32): 0x200000AE
target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
r0 (/32): 0x00000000
>> Flash Sector: 28-34 => 0x00003800 (3584)
     SRAM load : tmp/fl.04 => 0x20000120
     FLASH addr: reg r0 0x00003800
     SIZE  addr: reg r1 0x00000e00
     BUFFR addr: reg r2 0x20000120
3584 bytes written at address 0x20000120
downloaded 3584 bytes in 0.069238s (50.550 KiB/s)
r0 (/32): 0x00003800
r1 (/32): 0x00000E00
r2 (/32): 0x20000120
sp (/32): 0x20001000
pc (/32): 0x200000AE
target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
r0 (/32): 0x00000000
>> Flash Sector: 35-41 => 0x00004600 (3584)
     SRAM load : tmp/fl.05 => 0x20000120
     FLASH addr: reg r0 0x00004600
     SIZE  addr: reg r1 0x00000e00
     BUFFR addr: reg r2 0x20000120
3584 bytes written at address 0x20000120
downloaded 3584 bytes in 0.069181s (50.592 KiB/s)
r0 (/32): 0x00004600
r1 (/32): 0x00000E00
r2 (/32): 0x20000120
sp (/32): 0x20001000
pc (/32): 0x200000AE
target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
r0 (/32): 0x00000000
>> Flash Sector: 42-48 => 0x00005400 (3584)
     SRAM load : tmp/fl.06 => 0x20000120
     FLASH addr: reg r0 0x00005400
     SIZE  addr: reg r1 0x00000e00
     BUFFR addr: reg r2 0x20000120
3584 bytes written at address 0x20000120
downloaded 3584 bytes in 0.069107s (50.646 KiB/s)
r0 (/32): 0x00005400
r1 (/32): 0x00000E00
r2 (/32): 0x20000120
sp (/32): 0x20001000
pc (/32): 0x200000AE
target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
r0 (/32): 0x00000000
>> Flash Sector: 49-55 => 0x00006200 (3584)
     SRAM load : tmp/fl.07 => 0x20000120
     FLASH addr: reg r0 0x00006200
     SIZE  addr: reg r1 0x00000e00
     BUFFR addr: reg r2 0x20000120
3584 bytes written at address 0x20000120
downloaded 3584 bytes in 0.069117s (50.639 KiB/s)
r0 (/32): 0x00006200
r1 (/32): 0x00000E00
r2 (/32): 0x20000120
sp (/32): 0x20001000
pc (/32): 0x200000AE
target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
r0 (/32): 0x00000000
>> Flash Sector: 56-62 => 0x00007000 (3584)
     SRAM load : tmp/fl.08 => 0x20000120
     FLASH addr: reg r0 0x00007000
     SIZE  addr: reg r1 0x00000e00
     BUFFR addr: reg r2 0x20000120
3584 bytes written at address 0x20000120
downloaded 3584 bytes in 0.068143s (51.363 KiB/s)
r0 (/32): 0x00007000
r1 (/32): 0x00000E00
r2 (/32): 0x20000120
sp (/32): 0x20001000
pc (/32): 0x200000AE
target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
r0 (/32): 0x00000000
>> Flash Sector: 63-68 => 0x00007e00 (2584)
     SRAM load : tmp/fl.09 => 0x20000120
     FLASH addr: reg r0 0x00007e00
     SIZE  addr: reg r1 0x00000c00
     BUFFR addr: reg r2 0x20000120
2584 bytes written at address 0x20000120
downloaded 2584 bytes in 0.050122s (50.346 KiB/s)
r0 (/32): 0x00007E00
r1 (/32): 0x00000C00
r2 (/32): 0x20000120
sp (/32): 0x20001000
pc (/32): 0x200000AE
target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
r0 (/32): 0x00000000
>>>>   FLASH image: stop
>>>>    Verify: verify_image /rest/cvs/cheali-charger/./src/hardware/nuvoton-M0517/targets/imaxB6-clone/cheali-charger-imaxB6-clone_1.00-20150617_nuvoton-M0517.bin 0
target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000002e msp: 0x20000ff4
verified 34840 bytes in 0.226838s (149.990 KiB/s)
Trajanje init: 0 sec
Trajanje brisi: 2 sec
Trajanje pisi: 2 sec
Trajanje ukupno: 4 sec
.pre

^^ Update

.pre
dpavlin@x200:/rest/cvs/cheali-charger/utils/M0517_flash_tools/tcl$ openocd -f interface/stlink-v2.cfg -f target_MO517_linux.cfg 
Open On-Chip Debugger 0.9.0 (2015-05-28-17:08)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : clock speed 950 kHz
Info : STLINK v2 JTAG v23 API v2 SWIM v4 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 3.239563
Info : M0517.cpu: hardware has 4 breakpoints, 2 watchpoints


# in other terminal

dpavlin@x200:/rest/cvs/cheali-charger/utils/M0517_flash_tools$ telnet localhost 4444
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> source M0517_flash.tcl
FlashAprom

> FlashAprom /rest/cvs/cheali-charger/hex/unstable/cheali-charger-imaxB6-clone_1.99-20150727_nuvoton-M0517.hex

.pre

^ Serial port

* http://www.rcgroups.com/forums/showthread.php?t=1046318
* https://groups.google.com/forum/#!topic/cheali-charger/VATJQ4-GpVE%5B1-25%5D

.pre
1 2 3

1 - +5V
2 - TTL TX serial / Vout of LM35
3 - GND
.pre

^^ LogView

^^^ tsv

.pre
grep '$1' cheali.log | sed 's/;/\t/g' | xclip -selection clipboard -i
.pre

^ temperature sensor

cheali-charger version 1.99:

The "Hard way" (any temp probe):
1. connect external temp probe
2. check if there is 5V on temp. connector (between pin 1 (GND) and pin 3)
3. go to: "options"-> "calibrate"->"temp extern"
(first calibration point: point 0) 
  4. set "temp:" to your room temperature (~20�C) 
(second calibration point: point 1) 
  5. set "calib. p.:" to 1
  6. heat temp. sensor to 60�C
  7. set "temp:" to 60�C (the temperature sensor should be at 60�C at this moment)

The "easy way" (LM35, LM35DZ):
1. connect external temp probe
2. check if there is 5V on temp. connector (between pin 1 (GND) and pin 3)
2. check sensor output voltage, should be: ~0.20V (between pin 1 (GND) and pin 2)
3. go to: "options"-> "calibrate"->"temp extern"
(first calibration point: point 0) 
  4. set "temp:" to your room temperature (~20�C) 
(second calibration point: point 1) 
  5. set "calib. p.:" to 1
  6. disconnect temperature probe
  7. make a shortcut between pin 1 (GND) and pin 2 on the temperature connector (simulate sensor output voltage = 0V)
  8. set "temp:" to 0�C

^ backup calibration

^^ memory map

Table 6.13-1 Memory Address Map

| Block Name | Size | Start Address | End Address |
| AP-ROM | 8/16/32/64KB | 0x0000_0000 | 0x0000_1FFF (8KB) |
|  |  |  | 0x0000_3FFF (16KB) |
|  |  |  | 0x0000_7FFF (32KB) |
|  |  |  | 0x0000_FFFF (64KB) |
| Data Flash | 4KB | 0x0001_F000 | 0x0001_FFFF |
| LD-ROM | 4KB | 0x0010_0000 | 0x0010_0FFF |
| User Configuration | 1 Words | 0x0030_0000 | 0x0030_0000 |

^^ backup

.pre
> init
> dump_image aprom.bin 0x0 0x10000
dumped 65536 bytes in 0.638086s (100.300 KiB/s)

> dump_image flash_data.bin 0x1f000 0x1000
dumped 4096 bytes in 0.042080s (95.057 KiB/s)

> dump_image ldrom.bin  0x100000 0x1000
SWD DPIDR 0x0bb11477
Failed to read memory at 0x00100000

> dump_image config.bin 0x300000 0x1000
SWD DPIDR 0x0bb11477
Failed to read memory at 0x00300000
.pre

^^ create calibration for compile from backup

apply fix for python3 from https://github.com/dpavlin/cheali-charger/tree/python3

.pre
dpavlin@nuc:/nuc/cheali-charger/utils/eepromExtractor$ ls -al eeprom.bin
-r--r--r-- 1 dpavlin dpavlin 4096 Jul  5 10:54 eeprom.bin
dpavlin@nuc:/nuc/cheali-charger/utils/eepromExtractor$ ./eeprom.py
magic:  chli
version: 9.3.10
Data(
    magicString = (
        99,
        104,
        108,
        105,
    ),
    architecture = 16385,
    calibrationVersion = 9,
    programDataVersion = 3,
    settingVersion = 10,
    calibration = (
        Calibration(
            p = (
                CalibrationPoint(
                    x = 0,
                    y = 50,
                ),
                CalibrationPoint(
                    x = 17148,
                    y = 15976,
                ),
            ),
        ),
        Calibration(
            p = (
                CalibrationPoint(
                    x = 0,
                    y = 50,
                ),
                CalibrationPoint(
                    x = 17148,
                    y = 15976,
                ),
            ),
        ),
        Calibration(
            p = (
                CalibrationPoint(
                    x = 525,
                    y = 100,
                ),
                CalibrationPoint(
                    x = 5447,
                    y = 1000,
                ),
            ),
        ),
        Calibration(
            p = (
                CalibrationPoint(
                    x = 1919,
                    y = 100,
                ),
                CalibrationPoint(
                    x = 5827,
                    y = 300,
                ),
            ),
        ),
        Calibration(
            p = (
                CalibrationPoint(
                    x = 0,
                    y = 0,
                ),
                CalibrationPoint(
                    x = 1,
                    y = 1,
                ),
            ),
        ),
        Calibration(
            p = (
                CalibrationPoint(
                    x = 8000,
                    y = 5940,
                ),
                CalibrationPoint(
                    x = 8642,
                    y = 3479,
                ),
            ),
        ),
        Calibration(
            p = (
                CalibrationPoint(
                    x = 0,
                    y = 0,
                ),
                CalibrationPoint(
                    x = 21558,
                    y = 12728,
                ),
            ),
        ),
        Calibration(
            p = (
                CalibrationPoint(
                    x = 52287,
                    y = 1910,
                ),
                CalibrationPoint(
                    x = 45432,
                    y = 0,
                ),
            ),
        ),
        Calibration(
            p = (
                CalibrationPoint(
                    x = 0,
                    y = 0,
                ),
                CalibrationPoint(
                    x = 25736,
                    y = 3995,
                ),
            ),
        ),
        Calibration(
            p = (
                CalibrationPoint(
                    x = 0,
                    y = 0,
                ),
                CalibrationPoint(
                    x = 25736,
                    y = 3995,
                ),
            ),
        ),
        Calibration(
            p = (
                CalibrationPoint(
                    x = 0,
                    y = 0,
                ),
                CalibrationPoint(
                    x = 51320,
                    y = 7985,
                ),
            ),
        ),
        Calibration(
            p = (
                CalibrationPoint(
                    x = 0,
                    y = 0,
                ),
                CalibrationPoint(
                    x = 26220,
                    y = 4002,
                ),
            ),
        ),
        Calibration(
            p = (
                CalibrationPoint(
                    x = 0,
                    y = 0,
                ),
                CalibrationPoint(
                    x = 26150,
                    y = 3989,
                ),
            ),
        ),
        Calibration(
            p = (
                CalibrationPoint(
                    x = 0,
                    y = 0,
                ),
                CalibrationPoint(
                    x = 25169,
                    y = 3916,
                ),
            ),
        ),
        Calibration(
            p = (
                CalibrationPoint(
                    x = 0,
                    y = 0,
                ),
                CalibrationPoint(
                    x = 25405,
                    y = 3933,
                ),
            ),
        ),
        Calibration(
            p = (
                CalibrationPoint(
                    x = 525,
                    y = 100,
                ),
                CalibrationPoint(
                    x = 5457,
                    y = 1000,
                ),
            ),
        ),
        Calibration(
            p = (
                CalibrationPoint(
                    x = 3013,
                    y = 100,
                ),
                CalibrationPoint(
                    x = 9187,
                    y = 300,
                ),
            ),
        ),
    ),
    calibrationCRC = 53014,
    battery = (
        Battery(
            type = 6,
            capacity = 2000,
            cells = 4,
            Ic = 1000,
            Id = 410,
            Vc_per_cell = 4200,
            Vd_per_cell = 3000,
            minIc = 100,
            minId = 55,
            time = 1000,
            enable_externT = 1,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac73640>,
        ),
        Battery(
            type = 6,
            capacity = 3000,
            cells = 1,
            Ic = 3000,
            Id = 1000,
            Vc_per_cell = 4200,
            Vd_per_cell = 3000,
            minIc = 300,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac735c0>,
        ),
        Battery(
            type = 1,
            capacity = 2000,
            cells = 1,
            Ic = 2000,
            Id = 490,
            Vc_per_cell = 1800,
            Vd_per_cell = 850,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 1,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac73740>,
        ),
        Battery(
            type = 2,
            capacity = 3600,
            cells = 2,
            Ic = 3600,
            Id = 1000,
            Vc_per_cell = 1800,
            Vd_per_cell = 1000,
            minIc = 360,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac73640>,
        ),
        Battery(
            type = 0,
            capacity = 2000,
            cells = 3,
            Ic = 2000,
            Id = 1000,
            Vc_per_cell = 1,
            Vd_per_cell = 1,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac735c0>,
        ),
        Battery(
            type = 0,
            capacity = 2000,
            cells = 3,
            Ic = 2000,
            Id = 1000,
            Vc_per_cell = 1,
            Vd_per_cell = 1,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac73740>,
        ),
        Battery(
            type = 0,
            capacity = 2000,
            cells = 3,
            Ic = 2000,
            Id = 1000,
            Vc_per_cell = 1,
            Vd_per_cell = 1,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac73640>,
        ),
        Battery(
            type = 0,
            capacity = 2000,
            cells = 3,
            Ic = 2000,
            Id = 1000,
            Vc_per_cell = 1,
            Vd_per_cell = 1,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac735c0>,
        ),
        Battery(
            type = 0,
            capacity = 2000,
            cells = 3,
            Ic = 2000,
            Id = 1000,
            Vc_per_cell = 1,
            Vd_per_cell = 1,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac73740>,
        ),
        Battery(
            type = 0,
            capacity = 2000,
            cells = 3,
            Ic = 2000,
            Id = 1000,
            Vc_per_cell = 1,
            Vd_per_cell = 1,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac73640>,
        ),
        Battery(
            type = 0,
            capacity = 2000,
            cells = 3,
            Ic = 2000,
            Id = 1000,
            Vc_per_cell = 1,
            Vd_per_cell = 1,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac735c0>,
        ),
        Battery(
            type = 0,
            capacity = 2000,
            cells = 3,
            Ic = 2000,
            Id = 1000,
            Vc_per_cell = 1,
            Vd_per_cell = 1,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac73740>,
        ),
        Battery(
            type = 0,
            capacity = 2000,
            cells = 3,
            Ic = 2000,
            Id = 1000,
            Vc_per_cell = 1,
            Vd_per_cell = 1,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac73640>,
        ),
        Battery(
            type = 0,
            capacity = 2000,
            cells = 3,
            Ic = 2000,
            Id = 1000,
            Vc_per_cell = 1,
            Vd_per_cell = 1,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac735c0>,
        ),
        Battery(
            type = 0,
            capacity = 2000,
            cells = 3,
            Ic = 2000,
            Id = 1000,
            Vc_per_cell = 1,
            Vd_per_cell = 1,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac73740>,
        ),
        Battery(
            type = 0,
            capacity = 2000,
            cells = 3,
            Ic = 2000,
            Id = 1000,
            Vc_per_cell = 1,
            Vd_per_cell = 1,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac73640>,
        ),
        Battery(
            type = 0,
            capacity = 2000,
            cells = 3,
            Ic = 2000,
            Id = 1000,
            Vc_per_cell = 1,
            Vd_per_cell = 1,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac735c0>,
        ),
        Battery(
            type = 0,
            capacity = 2000,
            cells = 3,
            Ic = 2000,
            Id = 1000,
            Vc_per_cell = 1,
            Vd_per_cell = 1,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac73740>,
        ),
        Battery(
            type = 0,
            capacity = 2000,
            cells = 3,
            Ic = 2000,
            Id = 1000,
            Vc_per_cell = 1,
            Vd_per_cell = 1,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac73640>,
        ),
        Battery(
            type = 11,
            capacity = 2000,
            cells = 1,
            Ic = 2000,
            Id = 1000,
            Vc_per_cell = 3000,
            Vd_per_cell = 1,
            minIc = 200,
            minId = 100,
            time = 1000,
            enable_externT = 0,
            externTCO = 6000,
            enable_adaptiveDischarge = 0,
            DCRestTime = 30,
            capCutoff = 120,
            _0 = <v9_3_10.N11ProgramData7Battery3DOT_1E object at 0x7f3f4ac735c0>,
        ),
    ),
    programDataCRC = 13555,
    settings = Settings(
        backlight = 70,
        fanOn = 3,
        fanTempOn = 5000,
        dischargeTempOff = 6000,
        audioBeep = 1,
        minIc = 50,
        minId = 50,
        inputVoltageLow = 10000,
        adcNoise = 0,
        UART = 3,
        UARTspeed = 3,
        UARToutput = 1,
        menuType = 1,
    ),
    settingsCRC = 15640,
)
dpavlin@nuc:/nuc/cheali-charger/utils/eepromExtractor$ cp defaultCalibration.cpp ../../src/hardware/nuvoton-M0517/targets/imaxB6-clone/
.pre

^ serial tx and rx on chip pins

* pin 5 - P3.0 RX
* pin 7 - P3.1 TX

{file: M051-LQFP-pins.png}

{image: M051-LQFP-pins-800.png}

^ openocd upstream support for nuvoton

.pre
pi@pihdmi:~/openocd-rpi2-stm32/imax_b6 $ openocd -f rpi2-swd.cfg -f target/numicro.cfg
Open On-Chip Debugger 0.10.0+dev-01489-g06c7a53f1-dirty (2020-11-14-15:21)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
swd
cortex_m reset_config sysresetreq

Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : BCM2835 GPIO JTAG/SWD bitbang driver
Info : clock speed 1001 kHz
Info : SWD DPIDR 0x0bb11477
Info : NuMicro.cpu: hardware has 4 breakpoints, 2 watchpoints
Info : starting gdb server for NuMicro.cpu on 3333
Info : Listening on port 3333 for gdb connections
.pre

Program new version

.pre
> halt
target halted due to debug-request, current mode: Handler External Interrupt(6)
xPSR: 0x41000016 pc: 0x00000a70 msp: 0x20000f60
> flash write_bank 0 /nuc/cheali-charger/src/hardware/nuvoton-M0517/targets/imaxB6-clone/cheali-charger-imaxB6-clone_2.01-e10.3.12-20210623_nuvoton-M0517.bin
Nuvoton NuMicro: Flash Write ...
wrote 37776 bytes from file /nuc/cheali-charger/src/hardware/nuvoton-M0517/targets/imaxB6-clone/cheali-charger-imaxB6-clone_2.01-e10.3.12-20210623_nuvoton-M0517.bin to flash bank 0 at offset 0x00000000 in 0.906262s (40.706 KiB/s)

> reset
NuMicro.cpu -- clearing lockup after double fault
target halted due to debug-request, current mode: Handler HardFault
xPSR: 0x01000003 pc: 0xfffffffe msp: 0x20000eb0
Polling target NuMicro.cpu failed, trying to reexamine
NuMicro.cpu: hardware has 4 breakpoints, 2 watchpoints

.pre

This will brick mcu, so don't do it!

^ openocd 0.10 changes

https://github.com/dpavlin/M0517_flash_tools/tree/fix_openocd_0.10

Update cheali-charger/utils/M0517_flash_tools to branch fix_openocd_0.10

^^ update version

start openocd with raspberry pi configurtaion:

.pre
pi@pihdmi:~/openocd-rpi2-stm32/imax_b6 $ openocd -f target_M0517_rpi.cfg -s /nuc/cheali-charger/utils/M0517_flash_tools/tcl/ -f M0517_flash.tcl -f M0517_unlock.tcl
Open On-Chip Debugger 0.10.0+dev-01489-g06c7a53f1-dirty (2020-11-14-15:21)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
cortex_m reset_config sysresetreq

FlashAprom
EraseChip
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : BCM2835 GPIO JTAG/SWD bitbang driver
Info : clock speed 1001 kHz
Info : SWD DPIDR 0x0bb11477
Info : M0517.cpu: hardware has 4 breakpoints, 2 watchpoints
Info : starting gdb server for M0517.cpu on 3333
Info : Listening on port 3333 for gdb connections
Info : accepting 'telnet' connection on tcp/4444
.pre

connect and flash latest version

.pre
pi@pihdmi:~/openocd-rpi2-stm32/imax_b6 $ telnet localhost 4444
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
>
> FlashAprom /nuc/cheali-charger/src/hardware/nuvoton-M0517/targets/imaxB6-clone/cheali-charger-imaxB6-clone_2.01-e10.3.12-20210623_nuvoton-M0517.bin

> FlashAprom /nuc/cheali-charger/src/hardware/nuvoton-M0517/targets/imaxB6-clone/cheali-charger-imaxB6-clone_2.01-e10.3.12-20210705_nuvoton-M0517.bin

target halted due to debug-request, current mode: Thread
xPSR: 0xc1000000 pc: 0x00001000 msp: 0x20000ed0
target halted due to breakpoint, current mode: Thread
xPSR: 0x41000000 pc: 0x20000048 msp: 0x20001000
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x200000a2 msp: 0x20000fec
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
> reset
.pre

output from openocd:

.pre
pi@pihdmi:~/openocd-rpi2-stm32/imax_b6 $ cat openocd.sh
openocd -s /nuc/cheali-charger/utils/M0517_flash_tools/tcl -f target_M0517_rpi.cfg -f M0517_flash.tcl -f M0517_unlock.tcl
pi@pihdmi:~/openocd-rpi2-stm32/imax_b6 $ ./openocd.sh
Open On-Chip Debugger 0.10.0+dev-01489-g06c7a53f1-dirty (2020-11-14-15:21)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
cortex_m reset_config sysresetreq

Flash
EraseChip
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : BCM2835 GPIO JTAG/SWD bitbang driver
Info : clock speed 1001 kHz
Info : SWD DPIDR 0x0bb11477
Info : M0517.cpu: hardware has 4 breakpoints, 2 watchpoints
Info : starting gdb server for M0517.cpu on 3333
Info : Listening on port 3333 for gdb connections
Info : accepting 'telnet' connection on tcp/4444
Info : dropped 'telnet' connection
Info : accepting 'telnet' connection on tcp/4444
Image: /nuc/cheali-charger/src/hardware/nuvoton-M0517/targets/imaxB6-clone/cheali-charger-imaxB6-clone_2.01-e10.3.12-20210705_nuvoton-M0517.bin, type: bin; Size=34660; Sectors:68; FlashProces:(34660;3584,9;2404,1)
>>>>     Load FlashPgm to SRAM: NU_M051x.bin => 0x20000000
target halted due to debug-request, current mode: Thread
xPSR: 0xc1000000 pc: 0x00001144 msp: 0x20000fd8
>>>>     FlashInit:
target halted due to breakpoint, current mode: Thread
xPSR: 0x41000000 pc: 0x20000048 msp: 0x20001000
>>>>     FlashInit stop:
time init: 1 sec
>>>>     EreaseFlash: start
     FLASH sector addr: 0x00000000
     sectors to erease: 0x00000044
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x200000a2 msp: 0x20000fec
>>>>    FlashErease: stop
time erease: 1 sec
>>>>   FLASH image: /nuc/cheali-charger/src/hardware/nuvoton-M0517/targets/imaxB6-clone/cheali-charger-imaxB6-clone_2.01-e10.3.12-20210705_nuvoton-M0517.bin to 0x00000000
>> Flash Sector: 0-6 => 0x00000000 (3584)
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
>> Flash Sector: 7-13 => 0x00000e00 (3584)
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
>> Flash Sector: 14-20 => 0x00001c00 (3584)
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
>> Flash Sector: 21-27 => 0x00002a00 (3584)
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
>> Flash Sector: 28-34 => 0x00003800 (3584)
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
>> Flash Sector: 35-41 => 0x00004600 (3584)
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
>> Flash Sector: 42-48 => 0x00005400 (3584)
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
>> Flash Sector: 49-55 => 0x00006200 (3584)
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
>> Flash Sector: 56-62 => 0x00007000 (3584)
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
>> Flash Sector: 63-67 => 0x00007e00 (2404)
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000010c msp: 0x20000ff4
>>>>   FLASH image: stop
>>>>    Verify: verify_image /nuc/cheali-charger/src/hardware/nuvoton-M0517/targets/imaxB6-clone/cheali-charger-imaxB6-clone_2.01-e10.3.12-20210705_nuvoton-M0517.bin 0
time write: 1 sec
time summary: 3 sec
.pre
Board sticker: M8S PRO R4 S912 3G 32G DDR4 DQ

{toc: }

{image: M8S-PRO.jpg}

It doesn't have button soldered, it works like power button in android

Serial port is marked on bottom of board (tx/rx are from cpu perspective)

probably: https://www.geekbuying.com/item/MECOOL-M8S-PRO-S912-KODI-17-0-4K-HDR10-3GB-DDR4-32GB-eMMC-TV-Box-380737.html

^ Android info

Android 7.1 bootlog from serial: {file: m8s-android-bootlog.txt.gz}

.pre
U-Boot 2015.01-g9331ff1-dirty (Mar 15 2018 - 16:16:24)

DRAM:  3 GiB
...
        aml_dt soc: gxm platform: q20xrmii variant: 3g
        dtb 0 soc: gxm   plat: q20xrmii   vari: 2g
        dtb 1 soc: gxm   plat: q20xrmii   vari: 3g
      Find match dtb: 1
...
parts: 10
00:      logo	0000000002000000 1
01:  recovery	0000000002000000 1
02:       rsv	0000000000800000 1
03:       tee	0000000000800000 1
04:     crypt	0000000002000000 1
05:      misc	0000000002000000 1
06:      boot	0000000002000000 1
07:    system	0000000080000000 1
08:     cache	0000000020000000 2
09:      data	ffffffffffffffff 4

M8SPRO:/ # uname -a
Linux localhost 3.14.29 #46 SMP PREEMPT Thu Apr 12 19:43:12 CST 2018 armv8l

M8SPRO:/ # cat /proc/cmdline
rootfstype=ramfs init=/init console=ttyS0,115200 no_console_suspend earlyprintk=aml-uart,0xc81004c0 ramoops.pstore_en=1 ramoops.record_size=0x8000 ramoops.console_size=0x4000 androidboot.selinux=permissive logo=osd1,loaded,0x3d800000,1080p60hz maxcpus=8 vout=1080p60hz,enable hdmimode=1080p60hz cvbsmode=576cvbs hdmitx= cvbsdrv=0 pq= androidboot.firstboot=0 jtag=apao androidboot.hardware=amlogic mac=D0:76:58:0E:63:A3 androidboot.mac=D0:76:58:0E:63:A3 androidboot.slot_suffix=_a buildvariant=userdebug

M8SPRO:/ # cat /proc/cpuinfo
Processor	: AArch64 Processor rev 4 (aarch64)
processor	: 0
processor	: 1
processor	: 2
processor	: 3
processor	: 4
processor	: 5
processor	: 6
processor	: 7
Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 wp half thumb fastmult vfp edsp neon vfpv3 tlsi vfpv4 idiva idivt 
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

Hardware	: Amlogic
Serial		: 220a82006da41365fedf301742726826

M8SPRO:/ # free
		total        used        free      shared     buffers
Mem:       2876604416  2210639872   665964544           0    31326208
-/+ buffers/cache:     2179313664   697290752
Swap:       524283904           0   524283904

M8SPRO:/ # df
ilesystem        1K-blocks    Used Available Use% Mounted on
mpfs               1404592     504   1404088   1% /dev
tmpfs               1404592       0   1404592   0% /mnt
/dev/block/system   2031440  973788   1057652  48% /system
/dev/block/data    26969964 3050864  23919100  12% /data
/dev/block/cache     507848    2860    504988   1% /cache
/dev/block/tee         5115      45      5070   1% /tee
/dev/fuse          26969964 3050864  23919100  12% /mnt/runtime/default/emulated
/dev/fuse          26969964 3050864  23919100  12% /mnt/runtime/read/emulated
/dev/fuse          26969964 3050864  23919100  12% /mnt/runtime/write/emulated

.pre

^ recovery sd

https://www.cnx-software.com/2016/11/19/how-to-create-a-bootable-recovery-sd-card-for-amlogic-tv-boxes/

^ amlogic info

http://www.linux-meson.com/doku.php

^ armbian

https://forum.armbian.com/topic/12162-single-armbian-image-for-rk-aml-aw-aarch64-armv8/

.pre
dpavlin@nuc:~/Downloads$ xzcat Armbian_20.09_Arm-64_bullseye_current_5.8.5.img.xz | dd iflag=fullblock oflag=direct conv=fsync status=progress bs=1M of=/dev/sdb
dpavlin@nuc:~/Downloads$ sudo mount /dev/sdb1 /mnt/sdb1/
dpavlin@nuc:~/Downloads$ cd /mnt/sdb1/

root@nuc:/mnt/sdb1# cp u-boot-s905x-s912 u-boot.ext

root@nuc:/mnt/sdb1# vi extlinux/extlinux.conf

root@nuc:/mnt/sdb1# grep -v '^#' extlinux/extlinux.conf
LABEL Armbian
LINUX /zImage
INITRD /uInitrd

FDT /dtb/amlogic/meson-gxm-q201.dtb
APPEND root=LABEL=ROOTFS rootflags=data=writeback rw console=ttyAML0,115200n8 console=tty0 no_console_suspend consoleblank=0 fsck.fix=yes fsck.repair=yes net.ifnames=0

.pre

Note that this board uses *meson-gxm-q201.dtb* which is internal rmii to make ethernet work!

issue `reboot update` from android shell to boot from sdcard

^^ ath10k wifi sdio firmware

After booting, you will get error message about missing firmware:

.pre
[    7.861827] ath10k_sdio mmc2:0001:1: Failed to find firmware-N.bin (N between 2 and 6) from ath10k/QCA9377/hw1.0: -2
[    7.861838] ath10k_sdio mmc2:0001:1: could not fetch firmware files (-2)
.pre

Package `firmware-atheros` is installed, so it's a bit puzzeling what file is missing, however, if we go to

https://github.com/kvalo/ath10k-firmware.git

we can find sdio firmware at https://github.com/kvalo/ath10k-firmware/tree/master/QCA9377/hw1.0/untested

.pre
dpavlin@m8s:~/ath10k-firmware$ git remote -v
origin	https://github.com/kvalo/ath10k-firmware.git (fetch)
origin	https://github.com/kvalo/ath10k-firmware.git (push)

dpavlin@m8s:~/ath10k-firmware$ sudo cp QCA9377/hw1.0/untested/firmware-sdio-5.bin_WLAN.TF.1.1.1-00061-QCATFSWPZ-1 /lib/firmware/ath10k/QCA9377/hw1.0/firmware-sdio-5.bin
.pre

After running `nmtui` and configuring wifi it's available but dies after a while under load.

^^ kernel source

https://github.com/150balbes/Amlogic_s905-kernel

currently, I'm using

.pre
dpavlin@m8s:~/linux$ git remote -v
origin	https://github.com/xdarklight/linux (fetch)
origin	https://github.com/xdarklight/linux (push)
dpavlin@m8s:~/linux$ git branch
  master
  meson-mx-integration-5.11-20210124
  meson-mx-integration-5.13-20210503
* meson-mx-integration-5.13-20210523
dpavlin@m8s:~/linux$ cat mason-build.sh
# https://github.com/SLAzurin/armbian-aml-s8xx-kernel-build-steps

# https://github.com/xdarklight/linux

make -j 8 Image dtbs modules && sudo make modules_install dtbs_install install
.pre

Installing armbian kernel package doesn't work because /boot partition is vfat and not ext2/4

^^ u-boot source

https://github.com/150balbes/Amlogic_S905-u-boot

^^ balbes150 updates

installing linux image and headers does return error, but works

https://users.armbian.com/balbes150/

^ gpiod

.pre
sudo apt install gpiod
.pre

^^ button - gpio 2

.pre
root@arm-64:~# gpioget gpiochip0 2 # not pressed
1
root@arm-64:~# gpioget gpiochip0 2 # pressed
0
.pre

^^ led - gpio 9

.pre
root@arm-64:~# gpioset gpiochip0 9=0 # red

root@arm-64:~# gpioset gpiochip0 9=1 # blue (default)
.pre

^ u-boot

old https://github.com/endlessm/u-boot-meson

I wanted serial console which seems to be missing from armbian build above

wiki seems to suggest repository

https://gitlab.denx.de/u-boot/custodians/u-boot-amlogic

but we are going to use upstream u-boot

.pre
dpavlin@m8s:~/u-boot-amlogic$ git remote -v
github	https://github.com/u-boot/u-boot (fetch)

dpavlin@m8s:~/u-boot-amlogic$ libretech-cc_defconfig
dpavlin@m8s:~/u-boot-amlogic$ make -j 8
dpavlin@m8s:~/u-boot-amlogic$ cp u-boot.bin /boot/
.pre

abort u-boot with key press and boot new one with

.pre
fatload mmc 1 0x1000000 u-boot.bin
go 0x1000000
.pre

^ 2020-10 status for amlogic

U-Boot: Porting and Maintaining a Bootloader for a Multimedia SoC Family - Neil Armstrong, BayLibre SAS

https://youtu.be/u0-swEMDFp0
{image: GPIO 2.png}

Lamobo/BananaPi R1

http://linux-sunxi.org/Lamobo_R1

{toc: }

^ upgrade to unsupported armbian

This board was last supported on jessie, but it's fully supported in upstream so I did upgrade to latest Armbian as of 2021-05-29.

^^ u-boot

sdcard already had u-boot installed, so I didn't have to touch this in first step. To update
u-boot do following:

.pre
root@r1:/home/dpavlin# apt install u-boot-sunxi

root@r1:/home/dpavlin# dd conv=fsync,notrunc if=/usr/lib/u-boot/Lamobo_R1/u-boot-sunxi-with-spl.bin of=/dev/mmcblk0 bs=1024 seek=8
449+1 records in
449+1 records out
460103 bytes (460 kB, 449 KiB) copied, 0.0449233 s, 10.2 MB/s
.pre

^^ distribution

First, I did distribution update to stretch and buster and than added

.pre
root@r1:/home/dpavlin# cat /etc/apt/sources.list.d/armbian.list
deb http://beta.armbian.com buster main
.pre

^^ kernel

and installed latest sunxi kernel image

.pre
apt install linux-image-edge-sunxi
.pre

After reboot I was greeted with new kernel

.pre
root@r1:/home/dpavlin# uname -a
Linux r1 5.12.7-sunxi #trunk.33 SMP Fri May 28 07:03:36 UTC 2021 armv7l GNU/Linux
.pre

^^ configure switch

https://www.kernel.org/doc/html/latest/networking/dsa/b53.html

.pre
root@r1:/home/dpavlin# cat /etc/network/interfaces.d/br0
auto br0
iface br0 inet dhcp
#iface br0 inet manual
#	address 192.168.1.1
#	netmask 255.255.255.0
	bridge_ports eth0 wan lan1 lan2 lan3 lan4
	post-up for i in `seq 0 4`; do ip link set up dev lan${i}; done ; ip link set up dev wlan
	bridge_stp off
        bridge_waitport 0
	bridge_fd 0
.pre

Ports are (left-to-right, looking from back of board starting at edge towards hdmi connector):

.pre
br0: port 3(lan1) entered disabled state
br0: port 4(lan2) entered blocking state
br0: port 4(lan2) entered forwarding state
br0: port 4(lan2) entered disabled state
br0: port 5(lan3) entered blocking state
br0: port 5(lan3) entered forwarding state
br0: port 5(lan3) entered disabled state
br0: port 6(lan4) entered blocking state
br0: port 6(lan4) entered forwarding state
br0: port 6(lan4) entered disabled state
br0: port 2(wan) entered blocking state
br0: port 2(wan) entered forwarding state
.pre

^ switch connects all ports on boot

https://github.com/armbian/build/issues/511#issuecomment-258647387

^^ DSA config on armbian for r1

* https://github.com/armbian/build/issues/511

^ uart

Connect your UART adapter here:

UART0-RX: J13-P01
UART0-TX: J13-P02
GND: J12-P08

.pre
                          GND TX RX
             J12   o  o  o  o  o  o
{SD slot}          o  o  o  o

.pre

^ switch

https://www.mail-archive.com/netdev@vger.kernel.org/msg150526.html

^^ port mirroring

https://www.mail-archive.com/netdev@vger.kernel.org/msg150526.html

.pre
# ingress
      tc qdisc  add dev eth1 handle ffff: ingress
      tc filter add dev eth1 parent ffff:           \
               matchall skip_sw                      \
               action mirred egress mirror           \
               dev eth2
# egress
      tc qdisc add dev eth1 handle 1: root prio
      tc filter add dev eth1 parent 1:               \
               matchall skip_sw                       \
               action mirred egress mirror            \
               dev eth2
.pre

^ usb otg

http://git.rot13.org/?p=usb-otg;a=summary

^ usbproxy

make sure that there are no other usb modules loaded (libcomposite or g_*)

^^ mitm usb otg machine

.pre
dpavlin@r1:~/USBProxy$ git remote -v
origin  https://github.com/dominicgs/USBProxy (fetch)
origin  https://github.com/dominicgs/USBProxy (push)

dpavlin@r1:~/USBProxy/src/build$ sudo usb-mitm -l -v 058f -p 6387 -P PacketFilter_MassStorage
Loading plugins from /usr/local/lib/USBProxy/
vendorId=058f
productId=6387
cleaning up /tmp
removing 1
Made directory /tmp/gadget-SOOBVj for gadget
UnblockPassword=
Printing Config data
        Strings: 4
                DeviceProxy: DeviceProxy_LibUSB
                HostProxy: HostProxy_GadgetFS
                productId: 6387
                vendorId: 058f
        Vectors: 1
                Plugins:
                        PacketFilter_StreamLog
                        PacketFilter_MassStorage
Pointer: 1
                PacketFilter_StreamLog::file: 0xb6d779f0
Device: 12 01 00 02 00 00 00 40 8f 05 87 63 00 01 01 02 03 01
  Manufacturer: JetFlash
  Product:      Mass Storage Device
  Serial:       GUYOBHDU
        *Config(1): 09 02 20 00 01 01 00 80 32
                Interface(0):
                        *Alt(0): 09 04 00 00 02 08 06 50 00
                                EP(01): 07 05 01 02 00 02 00
                                EP(82): 07 05 82 02 00 02 00
HS Qualifier: 0a 06 00 02 00 00 00 40 01 00
         Config(1): 09 07 20 00 01 01 00 80 32
                Interface(0):
                        *Alt(0): 09 04 00 00 02 08 06 50 00
                                EP(01): 07 05 01 02 40 00 00
                                EP(82): 07 05 82 02 40 00 00
searching in [/tmp/gadget-SOOBVj]
Starting injector thread (14796) for [Injector].
Injector In FD[1/1]: 3
Starting setup writer thread (14799) for EP00.
Starting setup reader thread (14797) for EP00.
[80 06 00 03 00 00 ff 00]
[80 06 00 03 00 00 04 00]: 04 03 09 04
[80 06 02 03 09 04 ff 00]
[80 06 02 03 09 04 28 00]:
        28 03 4d 00 61 00 73 00 73 00 20 00 53 00 74 00 6f 00 72 00 61 00 67 00 65 00 20 00 44 00 65 00
        76 00 69 00 63 00 65 00
[80 06 01 03 09 04 ff 00]
[80 06 01 03 09 04 12 00]: 12 03 4a 00 65 00 74 00 46 00 6c 00 61 00 73 00 68 00
[80 06 03 03 09 04 ff 00]
[80 06 03 03 09 04 12 00]: 12 03 47 00 55 00 59 00 4f 00 42 00 48 00 44 00 55 00
[00 09 01 00 00 00 00 00]
Opened EP01
Opened EP82
Starting writer thread (14802) for EP01.
Starting reader thread (14803) for EP82.
Starting writer thread (14804) for EP82.
Starting reader thread (14801) for EP01.
[a1 fe 00 00 00 00 01 00]
[a1 fe 00 00 00 00 00 00]
01[31]: 55 53 42 43 01 00 00 00 24 00 00 00 80 00 06 12 00 00 00 24 00 00 00 00 00 00 00 00 00 00 00
CBW: (12), tag: 01 00 00 00

[80 06 03 03 09 04 ff 00]
[80 06 03 03 09 04 12 00]: 12 03 47 00 55 00 59 00 4f 00 42 00 48 00 44 00 55 00
[00 09 01 00 00 00 00 00]

.pre

^^ original target device

.pre
dpavlin@nuc:~$ journalctl -t kernel -f
Sep 01 11:10:04 nuc kernel: usb 2-4.4.2: new high-speed USB device number 45 using xhci_hcd
Sep 01 11:10:04 nuc kernel: usb 2-4.4.2: New USB device found, idVendor=058f, idProduct=6387
Sep 01 11:10:04 nuc kernel: usb 2-4.4.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Sep 01 11:10:04 nuc kernel: usb 2-4.4.2: Product: Mass Storage Device
Sep 01 11:10:04 nuc kernel: usb 2-4.4.2: Manufacturer: JetFlash
Sep 01 11:10:04 nuc kernel: usb 2-4.4.2: SerialNumber: GUYOBHDU
Sep 01 11:10:04 nuc kernel: usb-storage 2-4.4.2:1.0: USB Mass Storage device detected
Sep 01 11:10:04 nuc kernel: scsi host5: usb-storage 2-4.4.2:1.0

# BUT!

dpavlin@nuc:~$ sudo fdisk -l /dev/sdb
fdisk: cannot open /dev/sdb: No medium found

.pre

^ WiringPi

.pre
dpavlin@r1:~/BPI-WiringPi2$ git remote -v
lanefu  https://github.com/lanefu/WiringOtherPi (fetch)
lanefu  https://github.com/lanefu/WiringOtherPi (push)
origin  https://github.com/BPI-SINOVOIP/BPI-WiringPi2 (fetch)
origin  https://github.com/BPI-SINOVOIP/BPI-WiringPi2 (push)

dpavlin@r1:~/BPI-WiringPi2$ gpio readall
 +-----+-----+----------+------+---+-Orange Pi+---+---+------+---------+-----+--+
 | BCM | wPi |   Name   | Mode | V | Physical | V | Mode | Name     | wPi | BCM |
 +-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+
 |     |     |     3.3v |      |   |  1 || 2  |   |      | 5v       |     |     |
 |  12 |   8 |    SDA.0 |   IN | 0 |  3 || 4  |   |      | 5V       |     |     |
 |  11 |   9 |    SCL.0 |   IN | 0 |  5 || 6  |   |      | 0v       |     |     |
 |   6 |   7 |   GPIO.7 |   IN | 0 |  7 || 8  | 0 | IN   | TxD3     | 15  | 13  |
 |     |     |       0v |      |   |  9 || 10 | 0 | IN   | RxD3     | 16  | 14  |
 |   1 |   0 |     RxD2 |   IN | 0 | 11 || 12 | 0 | IN   | GPIO.1   | 1   | 110 |
 |   0 |   2 |     TxD2 |   IN | 0 | 13 || 14 |   |      | 0v       |     |     |
 |   3 |   3 |     CTS2 |   IN | 0 | 15 || 16 | 0 | IN   | GPIO.4   | 4   | 68  |
 |     |     |     3.3v |      |   | 17 || 18 | 0 | IN   | GPIO.5   | 5   | 71  |
 |  64 |  12 |     MOSI |   IN | 0 | 19 || 20 |   |      | 0v       |     |     |
 |  65 |  13 |     MISO |   IN | 0 | 21 || 22 | 0 | IN   | RTS2     | 6   | 2   |
 |  66 |  14 |     SCLK |   IN | 0 | 23 || 24 | 0 | IN   | CE0      | 10  | 67  |
 |     |     |       0v |      |   | 25 || 26 | 0 | IN   | GPIO.11  | 11  | 21  |
 |  19 |  30 |    SDA.1 |   IN | 0 | 27 || 28 | 0 | IN   | SCL.1    | 31  | 18  |
 |   7 |  21 |  GPIO.21 |   IN | 0 | 29 || 30 |   |      | 0v       |     |     |
 |   8 |  22 |  GPIO.22 |   IN | 0 | 31 || 32 | 0 | IN   | RTS1     | 26  | 200 |
 |   9 |  23 |  GPIO.23 |   IN | 0 | 33 || 34 |   |      | 0v       |     |     |
 |  10 |  24 |  GPIO.24 |   IN | 0 | 35 || 36 | 0 | IN   | CTS1     | 27  | 201 |
 |  20 |  25 |  GPIO.25 |   IN | 0 | 37 || 38 | 0 | IN   | TxD1     | 28  | 198 |
 |     |     |       0v |      |   | 39 || 40 | 0 | IN   | RxD1     | 29  | 199 |
 +-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+
 | BCM | wPi |   Name   | Mode | V | Physical | V | Mode | Name     | wPi | BCM |
 +-----+-----+----------+------+---+-Orange Pi+---+------+----------+-----+-----+


.pre

^ TMP75

.pre
root@r1:/etc/telegraf# i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- 49 -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         

.pre

^^ userland

* https://github.com/ManuelSchneid3r/RaspberryPi/blob/master/sensors/src/tmp.c

.pre
dpavlin@r1:~$ cc tmp.c -o tmp -lm
dpavlin@r1:~$ sudo ./tmp /dev/i2c-1 0x49
21.5

.pre

^^ kernel hwmomn lm75 driver

.pre
root@r1:~# echo lm75 0x49 > /sys/bus/i2c/devices/i2c-1/new_device 

root@r1:~# dmesg | tail -2
[68352.599623] lm75 1-0049: hwmon1: sensor 'lm75'
[68352.599719] i2c i2c-1: new_device: Instantiated device lm75 at 0x49

root@r1:/sys/bus/i2c/devices/i2c-1# sensors
sun4i_ts-isa-0000
Adapter: ISA adapter
SoC temperature:  +44.4°C  

lm75-i2c-1-49
Adapter: mv64xxx_i2c adapter
temp1:        +22.0°C  (high = +80.0°C, hyst = +75.0°C)
.pre

^ network performance

^^ kernel 3.4

.pre
root@r1:~# uname -a
Linux r1 3.4.113-sun7i #23 SMP PREEMPT Wed Jun 14 23:57:45 CEST 2017 armv7l GNU/Linux

root@r1:~# iperf3 --reverse --client nuc
Connecting to host nuc, port 5201
Reverse mode, remote host nuc is sending
[  4] local 192.168.3.238 port 58203 connected to 192.168.3.40 port 5201
[ ID] Interval           Transfer     Bandwidth
[  4]   0.00-1.00   sec   107 MBytes   897 Mbits/sec                  
[  4]   1.00-2.00   sec   110 MBytes   923 Mbits/sec                  
[  4]   2.00-3.00   sec   111 MBytes   935 Mbits/sec                  
[  4]   3.00-4.00   sec   107 MBytes   894 Mbits/sec                  
[  4]   4.00-5.00   sec   111 MBytes   927 Mbits/sec                  
[  4]   5.00-6.00   sec   110 MBytes   922 Mbits/sec                  
[  4]   6.00-7.00   sec   111 MBytes   928 Mbits/sec                  
[  4]   7.00-8.00   sec   111 MBytes   935 Mbits/sec                  
[  4]   8.00-9.00   sec   111 MBytes   928 Mbits/sec                  
[  4]   9.00-10.00  sec   111 MBytes   931 Mbits/sec                  
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.00  sec  1.08 GBytes   924 Mbits/sec  147             sender
[  4]   0.00-10.00  sec  1.07 GBytes   922 Mbits/sec                  receiver

iperf Done.

root@r1:~# iperf3 --client nuc
Connecting to host nuc, port 5201
[  4] local 192.168.3.238 port 58205 connected to 192.168.3.40 port 5201
[ ID] Interval           Transfer     Bandwidth       Retr  Cwnd
[  4]   0.00-1.00   sec  51.3 MBytes   428 Mbits/sec    0    239 KBytes       
[  4]   1.00-2.01   sec  52.5 MBytes   436 Mbits/sec    0    240 KBytes       
[  4]   2.01-3.02   sec  52.5 MBytes   436 Mbits/sec    0    245 KBytes       
[  4]   3.02-4.01   sec  50.0 MBytes   424 Mbits/sec    0    246 KBytes       
[  4]   4.01-5.02   sec  51.2 MBytes   429 Mbits/sec    0    247 KBytes       
[  4]   5.02-6.02   sec  52.5 MBytes   439 Mbits/sec    0    250 KBytes       
[  4]   6.02-7.03   sec  51.2 MBytes   427 Mbits/sec    0    253 KBytes       
[  4]   7.03-8.00   sec  48.8 MBytes   418 Mbits/sec    0    256 KBytes       
[  4]   8.00-9.02   sec  52.5 MBytes   432 Mbits/sec    0    256 KBytes       
[  4]   9.02-10.01  sec  51.2 MBytes   435 Mbits/sec    0    256 KBytes       
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.01  sec   514 MBytes   431 Mbits/sec    0             sender
[  4]   0.00-10.01  sec   514 MBytes   431 Mbits/sec                  receiver
.pre

^^ kernel 4.13

.pre
root@r1:~# uname -a
Linux r1 4.13.10-sunxi #57 SMP Mon Oct 30 00:08:27 CET 2017 armv7l GNU/Linux

root@r1:~# iperf3 --client nuc
Connecting to host nuc, port 5201
[  4] local 192.168.3.238 port 59520 connected to 192.168.3.40 port 5201
[ ID] Interval           Transfer     Bandwidth       Retr  Cwnd
[  4]   0.00-1.00   sec  67.9 MBytes   567 Mbits/sec    0    765 KBytes       
[  4]   1.00-2.01   sec  82.1 MBytes   687 Mbits/sec    0    840 KBytes       
[  4]   2.01-3.01   sec  65.7 MBytes   547 Mbits/sec    0   1.13 MBytes       
[  4]   3.01-4.02   sec  80.0 MBytes   669 Mbits/sec    0   1.13 MBytes       
[  4]   4.02-5.00   sec  76.2 MBytes   648 Mbits/sec    0   1.24 MBytes       
[  4]   5.00-6.00   sec  81.2 MBytes   681 Mbits/sec    0   1.24 MBytes       
[  4]   6.00-7.06   sec  82.5 MBytes   656 Mbits/sec    0   1.33 MBytes       
[  4]   7.06-8.00   sec  80.0 MBytes   712 Mbits/sec    0   1.33 MBytes       
[  4]   8.00-9.00   sec  78.8 MBytes   659 Mbits/sec    0   1.61 MBytes       
[  4]   9.00-10.00  sec  83.8 MBytes   702 Mbits/sec    0   2.08 MBytes       
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.00  sec   778 MBytes   653 Mbits/sec    0             sender
[  4]   0.00-10.00  sec   775 MBytes   650 Mbits/sec                  receiver

iperf Done.

root@r1:~# iperf3 --reverse --client nuc
Connecting to host nuc, port 5201
Reverse mode, remote host nuc is sending
[  4] local 192.168.3.238 port 59524 connected to 192.168.3.40 port 5201
[ ID] Interval           Transfer     Bandwidth
[  4]   0.00-1.00   sec  98.0 MBytes   822 Mbits/sec                  
[  4]   1.00-2.00   sec   112 MBytes   933 Mbits/sec                  
[  4]   2.00-3.00   sec   107 MBytes   904 Mbits/sec                  
[  4]   3.00-4.00   sec   107 MBytes   898 Mbits/sec                  
[  4]   4.00-5.00   sec   108 MBytes   904 Mbits/sec                  
[  4]   5.00-6.00   sec   108 MBytes   903 Mbits/sec                  
[  4]   6.00-7.00   sec   108 MBytes   904 Mbits/sec                  
[  4]   7.00-8.00   sec   108 MBytes   904 Mbits/sec                  
[  4]   8.00-9.00   sec   108 MBytes   904 Mbits/sec                  
[  4]   9.00-10.00  sec   107 MBytes   899 Mbits/sec                  
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.00  sec  1.05 GBytes   900 Mbits/sec   69             sender
[  4]   0.00-10.00  sec  1.05 GBytes   898 Mbits/sec                  receiver


.pre

^^ kernel 5.12.7

.pre
dpavlin@r1:~$ uname -a
Linux r1 5.12.7-sunxi #trunk.33 SMP Fri May 28 07:03:36 UTC 2021 armv7l GNU/Linux

dpavlin@r1:~$ iperf3 -c nuc
Connecting to host nuc, port 5201
[  5] local 192.168.3.238 port 50136 connected to 192.168.3.40 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.02   sec  41.9 MBytes   346 Mbits/sec    0    239 KBytes
[  5]   1.02-2.02   sec  53.8 MBytes   448 Mbits/sec    0    266 KBytes
[  5]   2.02-3.00   sec  42.5 MBytes   363 Mbits/sec    0    266 KBytes
[  5]   3.00-4.02   sec  53.8 MBytes   445 Mbits/sec    0    277 KBytes
[  5]   4.02-5.01   sec  53.8 MBytes   456 Mbits/sec    0    325 KBytes
[  5]   5.01-6.02   sec  48.1 MBytes   400 Mbits/sec    0    386 KBytes
[  5]   6.02-7.03   sec  48.8 MBytes   405 Mbits/sec    0    386 KBytes
[  5]   7.03-8.00   sec  46.2 MBytes   397 Mbits/sec    0    386 KBytes
[  5]   8.00-9.02   sec  53.8 MBytes   443 Mbits/sec    0    393 KBytes
[  5]   9.02-10.00  sec  51.2 MBytes   438 Mbits/sec    0    393 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec   494 MBytes   414 Mbits/sec    0             sender
[  5]   0.00-10.01  sec   494 MBytes   414 Mbits/sec                  receiver

iperf Done.
dpavlin@r1:~$ iperf3 -R -c nuc
Connecting to host nuc, port 5201
Reverse mode, remote host nuc is sending
[  5] local 192.168.3.238 port 50140 connected to 192.168.3.40 port 5201
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.01   sec  66.9 MBytes   559 Mbits/sec
[  5]   1.01-2.00   sec  69.8 MBytes   588 Mbits/sec
[  5]   2.00-3.00   sec  66.8 MBytes   560 Mbits/sec
[  5]   3.00-4.00   sec  67.6 MBytes   567 Mbits/sec
[  5]   4.00-5.00   sec  67.6 MBytes   568 Mbits/sec
[  5]   5.00-6.00   sec  65.3 MBytes   548 Mbits/sec
[  5]   6.00-7.00   sec  66.5 MBytes   558 Mbits/sec
[  5]   7.00-8.00   sec  65.4 MBytes   549 Mbits/sec
[  5]   8.00-9.00   sec  66.7 MBytes   560 Mbits/sec
[  5]   9.00-10.00  sec  65.2 MBytes   547 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.01  sec   672 MBytes   563 Mbits/sec   57             sender
[  5]   0.00-10.00  sec   668 MBytes   560 Mbits/sec                  receiver

iperf Done.
.pre
{toc: }

^ documentation

* https://www.turris.cz/doc/en/start

^^ reset modes

https://www.turris.cz/doc/en/howto/omnia_factory_reset

 Available reset modes:

    1 LED: Standard (re)boot
    2 LEDs: Rollback to latest snapshot
    3 LEDs: Rollback to factory reset
    4 LEDs: Re-flash router from flash drive
    5 LEDs or more: Boot to rescue shell

^ vlan

* https://www.turris.cz/doc/en/howto/vlan_settings_omnia

^ GPIO pinout

{image: omnia-pin-header.png}

^^ PWM same on all pins

* https://forum.turris.cz/t/gpio-documentation/2869/5

^ Debian

* https://github.com/tmshlvck/omnia-debian/wiki
* https://wiki.debian.org/InstallingDebianOn/TurrisOmnia

.pre
root@turris:/mnt/tmp# wget http://aule.elfove.cz/~brill/omnia-debian/omnia-medkit-20170330.tar.gz

# boot into rescue mode

root@(none):~# mount /dev/mmcblk0p1 /target/

root@(none):~# btrfs subvolume create /target/@debian

.pre

watchdog will timeout, but you will eventually have subvolume visible from u-boot (which is not case if you just create subvolume from Turris OS

.pre
root@turris:/# btrfs sub create @debian
Create subvolume './@debian'

root@turris:/# cd /@debian
root@turris:/@debian# tar xf /mnt/tmp/omnia-medkit-20170330.tar.gz 
root@turris:/@debian# btrfs fi df .
System, single: total=32.00MiB, used=4.00KiB
Data+Metadata, single: total=3.68GiB, used=2.25GiB
GlobalReserve, single: total=48.00MiB, used=0.00B

root@turris:/@debian# vi etc/network/interfaces
auto br0
iface br0 inet static
        bridge_ports wlan0 eth0 eth2
        address 192.168.3.254
        netmask 255.255.255.0
        gateway 192.168.3.1
root@turris:~# echo b > /proc/sysrq-trigger
[54760.278340] sysrq: SysRq : Resetting
[54760.282039] CPU1: stopping
   
U-Boot SPL 2015.10-rc2 (Aug 18 2016 - 20:43:35)
High speed PHY - Version: 2.0
SERDES0 card detect: NONE
   
Initialize Turris board topology
Detected Device ID 6820
board SerDes lanes topology details:
 | Lane #  | Speed |  Type       |
 --------------------------------
 |   0    |  5   |  PCIe0       |
 |   1    |  5   |  USB3 HOST0  |
 |   2    |  5   |  PCIe1       |
 |   3    |  5   |  USB3 HOST1  |
 |   4    |  5   |  PCIe2       |
 |   5    |  0   |  SGMII2      |
 --------------------------------
poll_op_execute: TIMEOUT
PCIe, Idx 0: detected no link
PCIe, Idx 1: detected no link
PCIe, Idx 2: detected no link
High speed PHY - Ended Successfully
DDR3 Training Sequence - Ver TIP-1.29.0
Memory config in EEPROM: 0x01
DDR3 Training Sequence - Switching XBAR Window to FastPath Window
DDR3 Training Sequence - Ended Successfully

   
U-Boot 2015.10-rc2 (Aug 18 2016 - 20:43:35 +0200), Build: jenkins-omnia-master-23
   
SoC:   MV88F6820-A0
       Watchdog enabled
I2C:   ready
SPI:   ready
DRAM:  1 GiB (ECC not enabled)
Enabling Armada 385 watchdog.
Disabling MCU startup watchdog.
Regdomain set to **
MMC:   mv_sdh: 0
SF: Detected S25FL164K with page size 256 Bytes, erase size 64 KiB, total 8 MiB
*** Warning - bad CRC, using default environment
   
Model: Marvell Armada 385 GP
Board: Turris Omnia SN: 0000000B0000B8E5
Regdomain set to **
SCSI:  MVEBU SATA INIT
SATA link 0 timeout.
SATA link 1 timeout.
AHCI 0001.0000 32 slots 2 ports 6 Gbps 0x3 impl SATA mode
flags: 64bit ncq led only pmp fbss pio slum part sxs
Net:   neta2
Hit any key to stop autoboot:  0
=> 

=> setenv debbootargs earlyprintk console=ttyS0,115200 rootfstype=btrfs rootwait root=/dev/mmcblk0p1 rootflags=subvol=@debian,commit=5 rw
=> setenv debboot 'setenv bootargs "$debbootargs cfg80211.freg=$regdomain"; btrload mmc 0 0x01000000 boot/vmlinuz @debian; btrload mmc 0 0x02000000 boot/dtb @debian; btrload mmc 0 0x03000000 boot/initrd.img @debian; bootz 0x01000000 0x03000000:$filesize 0x02000000'
=> saveenv
Saving Environment to SPI Flash...
SF: Detected S25FL164K with page size 256 Bytes, erase size 64 KiB, total 8 MiB
Erasing SPI flash...Writing to SPI flash...done

=> setenv defbootcmd "$bootcmd"
=> setenv debbootcmd 'i2c dev 1; i2c read 0x2a 0x9 1 0x00FFFFF0; setexpr.b rescue *0x00FFFFF0; if test $rescue -ge 2; then echo BOOT RESCUE; run rescueboot; else if test $rescue -ge 1; then echo BOOT eMMC TurrisOS FS; run mmcboot; else echo BOOT eMMC Debian FS; run debboot; fi; fi'
=> setenv bootcmd "$debbootcmd"
=> saveenv
Saving Environment to SPI Flash...
Erasing SPI flash...Writing to SPI flash...done
.pre

^ u-boot problem

.pre
Kernel image @ 0x1000000 [ 0x000000 - 0x332588 ]
Wrong Ramdisk Image Format
Ramdisk image is corrupt or invalid
.pre

https://docs.turris.cz/hw/omnia/serial-boot/#u-boot

update u-boot

.pre
=> dhcp
neta2:1 is connected to neta2.  Reconnecting to neta2
neta2 Waiting for PHY auto negotiation to complete............ done
BOOTP broadcast 1
BOOTP broadcast 2
BOOTP broadcast 3
BOOTP broadcast 4
BOOTP broadcast 5
*** Unhandled DHCP Option in OFFER/ACK: 208
*** Unhandled DHCP Option in OFFER/ACK: 208
DHCP client bound to address 192.168.4.113 (5583 ms)
*** Warning: no boot file name; using 'C0A80471.img'
Using neta2 device
TFTP from server 192.168.4.1; our IP address is 192.168.4.113
Filename 'C0A80471.img'.
Load address: 0x800000
Loading: *
TFTP error: 'file /var/tftp/C0A80471.img not found' (1)
Not retrying...
=> tftpboot 0x1000000 uboot-turris-omnia-spl.kwb
Using neta2 device
TFTP from server 192.168.4.1; our IP address is 192.168.4.113
Filename 'uboot-turris-omnia-spl.kwb'.
Load address: 0x1000000
Loading: #####################################
         2.6 MiB/s
done
Bytes transferred = 534240 (826e0 hex)
=> sf probe
SF: Detected S25FL164K with page size 256 Bytes, erase size 64 KiB, total 8 MiB
=> sf update 0x1000000 0 $filesize
device 0 offset 0x0, size 0x826e0
534240 bytes written, 0 bytes skipped in 10.563s, speed 51765 B/s
.pre

fix default variables and boot from mmc (I did 4 leds rescue before)

.pre
env default -a
saveenv
run mmcboot
.pre

^^ rescue image

.pre
root@x230:/var/tftp# wget https://repo.turris.cz/hbs/omnia/packages/turrispackages/rescue-image_3.4-1_arm_cortex-a9_vfpv3-d16.ipk
root@x230:/var/tftp# mkdir tmp
root@x230:/var/tftp# cd tmp/
root@x230:/var/tftp/tmp# tar xvf ../rescue-image_3.4-1_arm_cortex-a9_vfpv3-d16.ipk
./debian-binary
./data.tar.gz
./control.tar.gz
root@x230:/var/tftp/tmp# tar xvf data.tar.gz
./
./usr/
./usr/share/
./usr/share/rescue-image/
./usr/share/rescue-image/image.fit
./usr/share/rescue-image/image.fit.lzma
root@x230:/var/tftp/tmp# cp usr/share/rescue-image/image.fit.lzma ../
.pre

now flash new rescue

.pre
=> tftpboot ${kernel_addr_r} image.fit.lzma
Using neta2 device
TFTP from server 192.168.4.1; our IP address is 192.168.4.113
Filename 'image.fit.lzma'.
Load address: 0x800000
Loading: #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         ###########################
         2.4 MiB/s
done
Bytes transferred = 6115919 (5d524f hex)

=> sf probe
SF: Detected S25FL164K with page size 256 Bytes, erase size 64 KiB, total 8 MiB
=> sf update ${kernel_addr_r} 0x00100000 ${filesize}
device 0 offset 0x5d524f, size 0x22adb1
SPI flash failed in erase step
.pre

^ update from shell

.pre
opkg install u-boot-omnia
opkg install rescue-image

root@turris:~# nor-update -d
Verifying /dev/mtd0 against /usr/share/omnia/uboot-devel ...
a107291f748c9b3d9d96dd718e3e471a - /dev/mtd0
15b3b8e4100351677e85b983ef659921 - /usr/share/omnia/uboot-devel
Failed
Unlocking /dev/mtd0 ...
Erasing /dev/mtd0 ...

Writing from /usr/share/omnia/uboot-devel to /dev/mtd0 ...
Verifying /dev/mtd1 against /usr/share/rescue-image/image.fit.lzma ...
1ea91207d0fbd4479bb4c8b4a3957371 - /dev/mtd1
82194bc8fc95193cc3f3491a047b0c88 - /usr/share/rescue-image/image.fit.lzma
Failed
Unlocking /dev/mtd1 ...
Erasing /dev/mtd1 ...

Writing from /usr/share/rescue-image/image.fit.lzma to /dev/mtd1 ...
.pre

This will make route unbootable :-(

Reflash router via usb https://docs.turris.cz/hw/omnia/rescue-modes/#re-flash-router
^ pictures

^^ position of plastic clips to unclip after removing screws

{file: innobox-v80-case-clips-20210522_192312.jpg}

^^ top of board

{file: innobox-v80-top-20210522_192339.jpg}

^^ bottom of board

{file: innobox-v80-back-20210522_192256.jpg}

^ software version

Hardware version: 	 1.0
Active image: 	 2
Firmware image 1: 	 1.0.839
Firmware image 2: 	 1.1.966
Checksum of image 1: 	 34e4b3948d00a869d961283510a7eb08
Checksum of image 2: 	 a6e08754c908c237d1539cb143611697
Firmware bootloader: 	 1.9
CRC of bootloader: 	 a6e08754c908c237d1539cb143611697

^ serial

4 pins, pin 1 marked with triangle

1: TX
2: RX
3: GND
4: 3V3 (?)

^ serial output

(partial)

.pre
BGA IC
Xtal:1
DDR3 init.
DRAMC init done.
Calculate size.
DRAM size=128MB
Set new TRFC.

7512DRAMC V1.2.2 (0)


EN751221 at Fri Apr 16 11:48:25 CST 2021 version 1.9 free bootbase

Memory size 128MB

Set SPI Clock to 50 Mhz
spi_nand_probe: mfr_id=0xc8, dev_id=0x21
Using Flash ECC.
Detected SPI NAND Flash : _SPI_NAND_DEVICE_ID_F50L1G, Flash Size=0x8000000
bmt pool size: 81
BMT & BBT Init Success


>>>> [get_env_info] hw_id:InnboxV80_PW2
>>>> [set_gpio_define] g_hw_id:InnboxV80_PW2
Reset button GPIO is: 0
Press any key in 3 secs to enter boot command mode.
............................................................

Invalid Power GPIO, just return and don't turn on Power LED

NAND FLASH

>>>> CTC: boot_flag_addr: 53e0fff; flag: 1 version_addr:53e1000 version:1.9<FF><FF><FF><FF>

==> boot flag = 1
Decompress to 80002000 free_mem_ptr=80E00000 free_mem_ptr_end=807B0000
from slave
Uncompressing [LZMA] ...  done.
Initializing cgroup subsys cpuset
Initializing cgroup subsys cpu
Initializing cgroup subsys cpuacct
Linux version 3.18.21 (iskratel@2d7d74f016e9) (gcc version 4.6.3 (Buildroot 2015.08.1) ) #3 SMP Fri Apr 16 11:32:58 CST 2021
ISPRAM0: PA=00770000,Size=00010000,enabled
Config7: 0x80080500
memsize:120MB
EcoNet EN751221 SOC prom init
bootconsole [early0] enabled
CPU0 revision is: 00019558 (MIPS 34Kc)
Determined physical RAM map:
 memory: 077fe000 @ 00002000 (usable)
Wasting 64 bytes for tracking 2 unused pages
Zone ranges:
  Normal   [mem 0x00002000-0x077fffff]
Movable zone start for each node
Early memory node ranges
  node   0: [mem 0x00002000-0x077fffff]
Initmem setup node 0 [mem 0x00002000-0x077fffff]
Detected 1 available secondary CPU(s)
Primary instruction cache 64kB, VIPT, 4-way, linesize 32 bytes.
Primary data cache 32kB, 4-way, VIPT, cache aliases, linesize 32 bytes
PERCPU: Embedded 9 pages/cpu @810f3000 s5664 r8192 d23008 u36864
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 30478
Kernel command line:  es=1
PID hash table entries: 512 (order: -1, 2048 bytes)
Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
Writing ErrCtl register=0002e01a
Readback ErrCtl register=0002e01a
nmi base is 81124200
Memory: 110280K/122872K available (7640K kernel code, 1290K rwdata, 1624K rodata, 304K init, 551K bss, 12592K reserved)
SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=2, Nodes=1
Hierarchical RCU implementation.
NR_IRQS:64

tc3162_time_init: Init bus timeout and watchdog
plat_set_irq_affinity: cpu 0
plat_set_irq_affinity: cpu 0 vpe_id 0
plat_set_irq_affinity: irq_vpe0 1 irq_vpe1 0, irq = 10
plat_set_irq_affinity: irq num 10
plat_set_irq_affinity: cpu 0
plat_set_irq_affinity: cpu 0 vpe_id 0
plat_set_irq_affinity: irq_vpe0 1 irq_vpe1 0, irq = 33
plat_set_irq_affinity: irq num 33
CPU frequency 900.00 MHz
plat_time_init: Entered, mips_timer_ack ptr is [80006dd4]
 Using 200.000 MHz high precision timer.
r4k_clockevent_init: setup_irq OK, irq is [31]
console [ttyS0] enabled
console [ttyS0] enabled
bootconsole [early0] disabled
bootconsole [early0] disabled
Calibrating delay loop... 597.60 BogoMIPS (lpj=2988032)
pid_max: default: 32768 minimum: 301
.pre

^ boot loader

.pre
bldr> ?

?                                   Print out help messages.
help                                Print out help messages.
go                                  Booting the linux kernel.
decomp                              Decompress kernel image to ram.
memrl <addr>                        Read a word from addr.
memwl <addr> <value>                Write a word to addr.
dump <addr> <len>                   Dump memory content.
jump <addr>                         Jump to addr.
flash <dst> <src> <len> <oob>       Write to flash from src to dst(oob: write nand oob if 1).
imginfo                             Show images info.
spinand_rwtest                      Flash Test
bdstore <flash dst> <bin src>       Do backdoor config store
bdshow                              Show backdoor config
bdswitch[1|0]                       Enable or disable backdoor function
ddrcalswitch[1|0]                   Enable or disable ddr calibration funciton
drambistswitch[0|1|2]               disable or enable, and quick or normal test
xmdm <addr> <len>                   Xmodem receive to addr.
miir <phyaddr> <reg>                Read ethernet phy reg.
miiw <phyaddr> <reg> <value>        Write ethernet phy reg.
cpufreq <freq num> / <m> <n>        Set CPU Freq <156~450>(freq has to be multiple of 6)
ipaddr <ip addr>                    Change modem's IP.
httpd                               Start Web Server
mtd
bldr> bdshow
back door config is not support NAND Flash
.pre
{toc: }

Board name: H2C-RPI-B01

HDMI interface to CSI-2 interface
Chip: TC358743XBG
Support TK1 full-featured expansion board
Support Raspberry Pi (linux kernel version to 4.0 or above)
Limited by the performance of Raspberry itself, up to 1080p@25
Physical size: 65x30 mm, fixed hole position is the same as zero.

https://www.aliexpress.com/item/4000152180240.html

https://www.raspberrypi.org/forums/viewtopic.php?f=38&t=120702&start=400#p1339178

Lusya Upgraded version Raspberry Pi HDMI Adapter Board HDMI interface to CSI-2 TC358743XBG for 4B 3B 3B+ ZERO G11-011

^ /boot/config.txt

https://fluxcoil.net/hardwarerelated/raspberry_pi_4_tc358743

ensure that all options are enabled

.pre
   dtparam=i2c_arm=on
   dtparam=i2s=on
   dtparam=spi=on
   dtparam=i2c_vc=on
   dtparam=audio=on
   dtoverlay=vc4-fkms-v3d
   dtoverlay=dwc2
   dtoverlay=tc358743
   dtoverlay=tc358743-audio
   start_x=1
   gpu_mem=128 

.pre

^ setup

.pre
[    8.590920] tc358743 0-000f: tc358743 found @ 0x1e (bcm2835 I2C adapter)

root@pihdmi:/home/pi/CSI2_device_config# git remote -v
origin	https://github.com/6by9/CSI2_device_config (fetch)
origin	https://github.com/6by9/CSI2_device_config (push)

root@pihdmi:/home/pi/CSI2_device_config# cat edid.sh
v4l2-ctl --set-edid=file=1080P50EDID.txt --fix-edid-checksums

root@pihdmi:/home/pi/CSI2_device_config# sh -x edid.sh
+ v4l2-ctl --set-edid=file=1080P50EDID.txt --fix-edid-checksums

CTA-861 Header
  IT Formats Underscanned: yes
  Audio:                   yes
  YCbCr 4:4:4:             no
  YCbCr 4:2:2:             no

HDMI Vendor-Specific Data Block
  Physical Address:        3.0.0.0
  YCbCr 4:4:4 Deep Color:  no
  30-bit:                  no
  36-bit:                  no
  48-bit:                  no

CTA-861 Video Capability Descriptor
  RGB Quantization Range:  yes
  YCC Quantization Range:  no
  PT:                      Supports both over- and underscan
  IT:                      Supports both over- and underscan
  CE:                      Supports both over- and underscan

.pre

https://fluxcoil.net/hardwarerelated/raspberry_pi_4_tc358743

{image: H5a650680b5f549749cce0a1a1f258bc2d.png}

{image: Hf9554fe5db464123bc629f548d89b606S.jpg}

^ ustreamer

.pre
pi@pihdmi:~ $ git clone --depth=1 https://github.com/pikvm/ustreamer
pi@pihdmi:~ $ cd ustreamer/
pi@pihdmi:~/ustreamer $ make WITH_OMX=1
pi@pihdmi:~/ustreamer $ ./ustreamer --dv-timings --device=/dev/video0 --format=uyvy --encoder=omx \
 --workers=3 --persistent --drop-same-frames=30 --host=0.0.0.0 --port=8080
.pre
https://tasmota.github.io/docs/devices/LC-Technology-WiFi-Relay/#lc-technology-wifi-relay-quad-relay-note-older-versions-of-this-board-used-a-baud-rate-of-9600-so-if-115200-doesnt-work-try-9600

(note, older versions of this board used a baud rate of 9600, so if 115200 doesn't work, try 9600)~

Note: The template provided below did not work on an ESP-01 running Tasmota 8.1.0. It was necessary to manually enter the template in the Configure Template menu.

    In configuration open Configure Other paste this template and select activate

.pre
{"NAME":"LC Technology 4CH Relay","GPIO":[52,255,17,255,255,255,255,255,21,22,23,24,255],"FLAG":0,"BASE":18}
.pre

    Open Configure Module and set GPIO0, GPIO2, GPIO4 and GPIO5 as Relay1, Relay2, Relay3 and Relay4. Click Save.
    Disable SerialLog (type seriallog 0 in the Tasmota console)

Enter this command in console (configure the 1st rule)

.pre
Rule1
 on System#Boot do Backlog Baudrate 9600; SerialSend5 0 endon
 on Power1#State=1 do SerialSend5 A00101A2 endon
 on Power1#State=0 do SerialSend5 A00100A1 endon
 on Power2#State=1 do SerialSend5 A00201A3 endon
 on Power2#State=0 do SerialSend5 A00200A2 endon
 on Power3#State=1 do SerialSend5 A00301A4 endon
 on Power3#State=0 do SerialSend5 A00300A3 endon
 on Power4#State=1 do SerialSend5 A00401A5 endon
 on Power4#State=0 do SerialSend5 A00400A4 endon
.pre

Enable the rule (type rule1 1 in the Tasmota console)
https://tasmota.github.io/docs/devices/Nedis-WIFIP310FWT/

https://templates.blakadder.com/nedis_WIFIP310FWT.html

Description: 3 port AC outlets (European Schucko Type F) + 4 USB power outlets

Power input: 16 A - 230 VAC

Max. Power: 3680 W

Power output: USB: 5 VDC /2.4 A each

^ mapping

| GPIO # | Component |
| GPIO00 | None |
| GPIO01 | Led1i |
| GPIO02 | None |
| GPIO03 | Button1 |
| GPIO04 | Relay2 |
| GPIO05 | Relay1 |
| GPIO09 | None |
| GPIO10 | None |
| GPIO12 | None |
| GPIO13 | Relay3 |
| GPIO14 | Relay4 |
| GPIO15 | None |
| GPIO16 | None |
| FLAG | Analog |

^ Template:

.pre
{"NAME":"Nedis WIFIP310","GPIO":[0,56,0,17,22,21,0,0,0,23,24,0,0],"FLAG":1,"BASE":18}
.pre

^ new template for version 9

.pre
IO":[0,320,0,32,225,224,0,0,0,226,227,0,0,4704],"FLAG":0,"BASE":18}
.pre
{image: pir-pinout.jpg}

^ BISS001 module

BISS001 - Micro Power PIR Motion Detector IC

* Input voltage: 3-5 V
* Hi: 0.7*Vdd = 0.7 * 5 V = 3.5 V
* Lo: 0.3*Vdd = 0.3 * 5 V = 1.5 V

^ HC-SR501 module

Technical data of the HC-SR501 Motion and Sensor Modules:

.pre
Input voltage: 4.5 V - 20 V
Digital output when motion is detected: 3.3 V (high)
Digital output with no movement on the HC-SR501: 0 V (low)
Working temperature in the environment: -15 � C to 70 � C
Delay Time 0.5 to 200 seconds
Angle of coverage: 100 �
Reach 5m - 7m
Size of the HC-SR501 motion:

Sensor Lens diameter: 23mm
Length: 24.03mm
Width: 32.34mm
Height (with lens): 24.66mm
Center screw hole spacing: 28 mm
Screw hole diameter: 2mm (M2)
.pre

^ Collect pir data using Linux gpio and send it to mqtt

both pots are all the way to the left (if jumper is on the left toword edge of board) to make minimal timeout

{file: pir.sh}

^^ gpio-utils

gpio-utils exists on Raspberry Pi

.pre
#!/bin/sh -e

led=/sys/devices/platform/rpi_control_board/leds/d1/brightness

# pir sensor connceted to 5V, GPIO12, GND
sudo stdbuf -oL -eL gpio-event-mon -n gpiochip0 -o 12 -r -f | while read gpio event time dir edge ; do
	case $dir in
		rising)
			echo -n "^"
			echo 1 > $led
			;;
		falling)
			echo -n "_"
			echo 0 > $led
			;;
		*)
			echo -n "?"
			;;
	esac
done
.pre

^^ gpiod

alternative version using gpiod package available on sunxi

.pre
#!/bin/sh -e

led=/sys/class/leds/orangepi:red:status/brightness

# pir sensor connceted to 5V, PA6, GND
sudo stdbuf -oL -eL gpiomon 0 6 | while read event dir edge time ; do
	echo "# $dir"
	case $dir in
		RISING)
			echo -n "^"
			echo 1 > $led
			;;
		FALLING)
			echo -n "_"
			echo 0 > $led
			;;
		*)
			echo -n "?"
			;;
	esac
done
.pre
{toc: }

This page tries to document my experiments using accelerometers

^ ADXL335

Board: GY-61.

    ADXL335 3-axis Accelerometer
    On-board 3.3V Voltage Regulator
    Analog voltage output centered at 1.65V
    Suitable for connection to 5V and 3.3V systems

    Supply Voltage: 3V - 5V
    Full scale range: +/-3g
    Sensitivity: 300mV/g (Typ)

^ MPU-9250

Board: Grove - IMU 10DOF v1.1

https://wiki.seeedstudio.com/Grove-IMU_10DOF/

{file: Grove - IMU 10DOF v1.1.pdf}

MPU-9250 addr: 0x68
BMP180 addr: 0x77

This board has 5V -> 3V3 level shifter but works with 3V3 as VCC

.pre
root@rpi4:~# i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- 77

root@rpi4:~# modprobe configs
root@rpi4:~# zgrep INV /proc/config.gz
CONFIG_INV_MPU6050_IIO=m
CONFIG_INV_MPU6050_I2C=m
# CONFIG_INV_MPU6050_SPI is not set

root@rpi4:~# modprobe inv-mpu6050-i2c

root@rpi4:~# echo mpu9250 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
[Sat Jan  9 14:10:25 2021] inv-mpu6050-i2c 1-0068: mounting matrix not found: using identity...
[Sat Jan  9 14:10:25 2021] inv-mpu6050-i2c 1-0068: 1-0068 supply vddio not found, using dummy regulator
[Sat Jan  9 14:10:25 2021] inv-mpu6050-i2c 1-0068: trigger probe fail -22
[Sat Jan  9 14:10:25 2021] inv-mpu6050-i2c: probe of 1-0068 failed with error -22
[Sat Jan  9 14:10:25 2021] i2c i2c-1: new_device: Instantiated device mpu9250 at 0x68

root@rpi4:~# echo bmp180 0x77 > /sys/class/i2c-adapter/i2c-1/new_device
[Sat Jan  9 14:12:17 2021] i2c i2c-1: new_device: Instantiated device bmp180 at 0x77
[Sat Jan  9 14:12:17 2021] bmp280 1-0077: 1-0077 supply vddd not found, using dummy regulator
[Sat Jan  9 14:12:17 2021] bmp280 1-0077: 1-0077 supply vdda not found, using dummy regulator
[Sat Jan  9 14:12:17 2021] bmp280 1-0077: non-rising trigger given for EOC interrupt, trying to enforce it
[Sat Jan  9 14:12:17 2021] bmp280 1-0077: unable to request DRDY IRQ

root@rpi4:~# iio_info
Library version: 0.16 (git tag: v0.16)
Compiled with backends: local xml ip usb serial
IIO context created with local backend.
Backend version: 0.16 (git tag: v0.16)
Backend description string: Linux rpi4 5.4.79-v7l+ #1373 SMP Mon Nov 23 13:27:40 GMT 2020 armv7l
IIO context has 1 attributes:
	local,kernel: 5.4.79-v7l+
IIO context has 1 devices:
	iio:device0: bmp180
		2 channels found:
			pressure:  (input)
			3 channel-specific attributes found:
				attr  0: input value: 100.646000000
				attr  1: oversampling_ratio value: 8
				attr  2: oversampling_ratio_available value: 1 2 4 8
			temp:  (input)
			3 channel-specific attributes found:
				attr  0: input value: 24800
				attr  1: oversampling_ratio value: 1
				attr  2: oversampling_ratio_available value: 1
.pre

Hm. bmp180 works, mpu9250 doesn't

It needs full device tree overlay https://github.com/dpavlin/linux-gpio-pinout/blob/master/device-tree/grove-imu10dof.dts
WB3-12 360 Degree Microwave Motion Detector Module [12V-35V]

Features:
Working Voltage: 12V ~ 35V DC
Quiescent Current: <7mA
Output Type: Digital
Default Delay Time: 1S (1~120S adjustment delay, please explain in advance)
Sensing Distance: 5m ~ 8m (default setting 6 meters)
Detection Angle: 180� x 360�
Output Signal: 3.3V , Low: 0V 
Pin Number: 3 Pins
Operating Temperature: -20�C ~ +80�C
Size: 17.5mm x 23mm / (round plate D25)

In my testing works on 5V, has 10s delay on trigger.
{file: iio.conf}

{image: orangepiplus2_info.jpg}

http://www.orangepi.org/orangepiplus2/

https://www.armbian.com/orange-pi-plus-2/

SoC	H3 @ 1.2GHz[1]
DRAM	2GiB DDR3 @ ?MHz (H5TC4G83AFR-PBA)
NAND	16GB EMMC Flash (in 2016 KLMAG2GEND-B031 but now slower KLMAG2WEPD-B031)
Power	DC 5V @ 2A (4.0mm/1.7mm barrel plug - centre positive)
Features
Video	HDMI (HDCP, CEC), CVBS
Audio	3.5 mm Jack, HDMI, Microphone
Network	10/100/1000Mbps Ethernet (Realtek RTL8211E), WiFi 802.11 b/g/n (Realtek RTL8189ETV)
Storage	�SD (max 64GB), SATA 2.0 (via GL830 USB-to-SATA bridge, +5V power on JST XH 2.5mm connector)
USB	4 USB 2.0 Host (via FE1.1s hub), 1 USB 2.0 OTG

^ bme280 i2c temperature/humidity/pressure

.pre
/home/dpavlin/linux-gpio-pinout/overlay-load.sh /boot/dtb-`uname -r`/overlay/*h3*i2c0*

root@opip:/home/dpavlin/linux-gpio-pinout# i2cdetect -y 2
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- 76 --
.pre

Check i2c address in datasheet

Connecting SDO to GND results in slave
address 1110110 (0x76); connection it to V DDIO results in slave address 1110111 (0x77)

.pre
root@opip:/home/dpavlin/linux-gpio-pinout# zgrep BMP280 /proc/config.gz
CONFIG_BMP280=m
CONFIG_BMP280_I2C=m
CONFIG_BMP280_SPI=m

root@opip:/home/dpavlin/linux-gpio-pinout# echo bmp280 0x76 > /sys/bus/i2c/devices/i2c-2/new_device
root@opip:/home/dpavlin/linux-gpio-pinout# [Sat Jan  2 11:43:58 2021] i2c i2c-2: new_device: Instantiated device bmp280 at 0x76
[Sat Jan  2 11:43:58 2021] bmp280 2-0076: supply vddd not found, using dummy regulator
[Sat Jan  2 11:43:58 2021] bmp280 2-0076: supply vdda not found, using dummy regulator
[Sat Jan  2 11:43:58 2021] bmp280 2-0076: bad chip id: expected 58 got 60
[Sat Jan  2 11:43:58 2021] bmp280: probe of 2-0076 failed with error -22

.pre

So it's not BMP280, but BME280.

Using https://www.raspberrypi-spy.co.uk/2016/07/using-bme280-i2c-temperature-pressure-sensor-in-python/
I downloaded and modified for python3 {file: bme280.py}

.pre
root@opip:/home/dpavlin# ./bme280.py
Chip ID : 96
Version : 0
Temperature : 24.65 C
Pressure : 998.4304559219445 hPa
Humidity : 41.458674890198445 %e
.pre

So let's try with correct sensor name

.pre
root@opip:/sys/bus/i2c/devices/i2c-2# echo bme280 0x76 > /sys/bus/i2c/devices/i2c-2/new_device
[Sat Jan  2 12:32:01 2021] bmp280 2-0076: supply vddd not found, using dummy regulator
[Sat Jan  2 12:32:01 2021] bmp280 2-0076: supply vdda not found, using dummy regulator
[Sat Jan  2 12:32:01 2021] i2c i2c-2: new_device: Instantiated device bme280 at 0x76

root@opip:~# apt install libiio-utils

root@opip:~# iio_info
Library version: 0.16 (git tag: v0.16)
Compiled with backends: local xml ip usb serial
IIO context created with local backend.
Backend version: 0.16 (git tag: v0.16)
Backend description string: Linux opip 5.10.0-rc7-sunxi #20.11.3 SMP Fri Dec 11 21:18:30 CET 2020 armv7l
IIO context has 1 attributes:
	local,kernel: 5.10.0-rc7-sunxi
IIO context has 1 devices:
	iio:device0: bme280
		3 channels found:
			humidityrelative:  (input)
			2 channel-specific attributes found:
				attr  0: input value: 40775
				attr  1: oversampling_ratio value: 16
			pressure:  (input)
			2 channel-specific attributes found:
				attr  0: input value: 99.809761718
				attr  1: oversampling_ratio value: 16
			temp:  (input)
			2 channel-specific attributes found:
				attr  0: input value: 25350
				attr  1: oversampling_ratio value: 2
.pre

^^ collect using telegraf

.pre
root@opip:/etc/telegraf/telegraf.d# ../telegraf --config iio.conf --test
2021-01-02T12:39:39Z I! Starting Telegraf
> iio,host=opip,name=bme280 humidityrelative=39.934,pressure=99.801214843,temperature=25.66 1609591179000000000
.pre
System Information
        Manufacturer: LENOVO
        Product Name: 20S1SBH600
        Version: ThinkPad T14 Gen 1
        Serial Number: PF22JXW6
        UUID: 6f7eec4c-2d1b-11b2-a85c-8372c07ecbde
        Wake-up Type: Power Switch
        SKU Number: LENOVO_MT_20S1_BU_Think_FM_ThinkPad T14 Gen 1
        Family: ThinkPad T14 Gen 1

^ sound

.pre
[    4.645562] sof-audio-pci 0000:00:1f.3: hda codecs found, mask 5
[    4.645563] sof-audio-pci 0000:00:1f.3: using HDA machine driver skl_hda_dsp_generic now
[    4.645566] sof-audio-pci 0000:00:1f.3: DMICs detected in NHLT tables: 2
[    4.645590] sof-audio-pci 0000:00:1f.3: firmware: failed to load intel/sof/sof-cml.ri (-2)
[    4.645591] sof-audio-pci 0000:00:1f.3: Direct firmware load for intel/sof/sof-cml.ri failed with error -2
[    4.645593] sof-audio-pci 0000:00:1f.3: error: request firmware intel/sof/sof-cml.ri failed err: -2
[    4.645593] sof-audio-pci 0000:00:1f.3: error: failed to load DSP firmware -2
.pre

firmware is not part of debian yet https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=960788

https://github.com/thesofproject/sof-bin
^ pcsc

.pre
dpavlin@x1:~$ sudo apt install pcscd pcsc-tools

dpavlin@x1:~$ wget https://www.eid.hr/sites/default/files/eidmiddleware_v3.2.0_amd64.deb

dpavlin@x1:~$ sudo dpkg -i eidmiddleware_v3.2.0_amd64.deb

dpavlin@x1:~$ /usr/lib/akd/eidmiddleware/Client

.pre

^ eid

Ove upute su bazirane na emardovom postu.

Evo za potpisivanje sa osobnim preko linuxa.
Skoro sve sam dobio osim tog secure pin readeara
trebao bi biti enablean je sa opcijom
"provider-eidosobna-allow-protected-auth"
ali meni to ne radi.

Probajte ako neko može to još dobit onda bismo
postali idealni eGradjanininini

aktiviraj karticu pomoću pina na sigurnoj omotnici
instaliraj middleware 3.2.0
https://www.eid.hr/hr/eoi/clanak/programski-paket-eid-middleware

.pre
$ /usr/lib/akd/eidmiddleware/Client

postavi konfiguraciju za gpgsm i externi pkcs11 driver

$ mkdir .gnupg

$ cat ~/.gnupg/gpg-agent.conf
scdaemon-program /usr/bin/gnupg-pkcs11-scd

$ cat ~/.gnupg/gnupg-pkcs11-scd.conf
# pin cache period in seconds
pin-cache 5
providers eidosobna
provider-eidosobna-library /usr/lib/akd/eidmiddleware/pkcs11/libEidPkcs11.so
provider-eidosobna-allow-protected-auth

check:
$ gpg --card-status
should list something about card
$ echo "SCD LEARN" | gpg-agent --server gpg-connect-agent
should show some key info

$ gpgsm --import < /usr/lib/akd/eidmiddleware/certificates/AKDCARoot.pem
gpgsm: total number processed: 1
gpgsm:               imported: 1
$ gpgsm --import < /usr/lib/akd/eidmiddleware/certificates/HRIDCA.pem
gpgsm: total number processed: 1
gpgsm:               imported: 1
$ gpgsm --learn-card

# check: this should list keys learned from the card:
$ gpgsm --list-keys

Put the fingerprint of your root CA to "~/.gnupg/trustlist.txt".
After fingerprint append " S" (space S without quotes)
$ cat ~/.gnupg/trustlist.txt
# /CN=AKDCA Root/O=AKD d.o.o./C=HR/2.5.4.97=VATHR-99993087891
99:99:A6:C0:7A:1B:20:89:9E:89:6C:A1:A3:AD:D9:65:34:39:94:58 S

# use default key ID for signing
$ cat ~/.gnupg/gpgsm.conf
# use specific key ID for signing (choose key ID from gpgsm --list-keys)
default-key 0x1234ABCD

# use default key ID for signing
$ gpgsm --detach-sign file.txt > file.txt.sgn

# use specific key ID for signing (choose key ID from gpgsm --list-keys)
$ gpgsm --detach-sign -u 0x1234ABCD file.txt > file.txt.sgn
... dialog to enter card PIN for the chosen key will appear ...

# verify the signature
$ gpgsm --verify file.txt.sgn file.txt

# kill agent after use (eventual pins cached)
$ gpgconf --kill gpg-agent
.pre

^ firefox

preferences > privacy & security > certificates > security devices > load

/usr/lib/akd/eidmiddleware/pkcs11/libEidPkcs11.so
https://github.com/icebreaker-fpga/icebreaker

iCE40UP5K

interesting ice40 projects:

^ usb analyzer

https://github.com/smunaut/iua
https://youtu.be/JjU5OQCWgms

^ usb audio device

part 1: https://youtu.be/4-JE2nZt0sk
part 2: https://youtu.be/UD2h8IuLXCQ

https://github.com/smunaut/ice40-playground/tree/master/projects/usb_audio
https://twitter.com/tnt/status/1335354626791665671

> tnt @tnt

Turned my #fomu into a usb sound card with midi output and also stereo headphones out. (USB audio spec compliant so all works out of the box)

Code is now upstream :

* FOMU support in no2bootloader (alternate to foboot, better imho for single purpose projects) https://github.com/no2fpga/no2bootloader/

* USB Audio code (hw/fw) in https://github.com/smunaut/ice40-playground/tree/master/projects/usb_audio with support for fomu/icebreaker/bitsy

Ping if you want help port to other boards

> Pepijn de Vos @pepijndevos

Wait how do you connect *anything* to the fomu? Solder wires to these capacitive tabs?

> tnt @tnt

Yeah, I soldered to the 4 IOs.

* #1 is wired as a button for DFU recovery (wired to a N/C pin of DIN plug)
* #2&3 are wired as PDM audio out with RC filter & DC block cap to the 3.5mm jack
* #4 is wired as the MIDI TX pin
datasheet: {file: dsm501.pdf}

DMS501A - 2mm pin pitch, DMS501B - 2.54 mm

5V, 90mA

1 minute stabilization after power up

sum time of low (0.7v) for measurement interval, divide by time

^ PINOUT I/O DESCRIPTION

| Pin number | Pin name | Description |
| #1 | Control | Vout 1 control |
| #2 | Vout 2 | Vout 2 output factory calibrated PWM output for density of particles over 1 �m. |
| #3 | Vcc | Positive power supply DC 5V |
| #4 | Vout 1 | Vout 1 output (PWM) |
| #5 | GND | Ground |

{image: dms501-5pins.png}

^^ control pin 1

resistor between pin 1 and ground (square pin on board) to control vout 1 output (pin 4)

| Resistor value | Description |
| open | Preset sensitivity (over 2.5 �m) |
| 47K | Half sensitivity (over 1.75 �m) |
| 18.2K | Equal sensitivity of Vout 2 (over 1 �m) |

^ arduino

* Nice library, but inside repository https://github.com/richardhmm/DIYRepo/tree/master/arduino/libraries/DSM501
* interrupt driven version https://github.com/Sovichea/dsm501-interrupt/

I tried both of them and on my module they don't report sane results when compared with other sensors.

^ platformio

https://primalcortex.wordpress.com/2020/05/23/an-esp8266-air-quality-monitor-based-on-the-dsm501a-dust-sensor/
https://github.com/fcgdam/ESP8266_AirQuality

.pre
dpavlin@nuc:/nuc/esp8266/ESP8266_AirQuality$ git remote -v
origin  https://github.com/fcgdam/ESP8266_AirQuality (fetch)
origin  https://github.com/fcgdam/ESP8266_AirQuality (push)

# edit config
dpavlin@nuc:/nuc/esp8266/ESP8266_AirQuality$ vi src/secrets.h

dpavlin@nuc:/nuc/esp8266/ESP8266_AirQuality$ pio run

dpavlin@nuc:/nuc/esp8266/ESP8266_AirQuality$ pio run -t upload --device-port /dev/ttyUSB2
.pre

Pins:

| Wemos D1 +5V | DSM501a +5V |
| Wemos D1 D6 | DSM501a PM 1.0 pin |
| Wemos D1 D5 | DSM501a PM 2.5 pin< |
| Wemos D1 GND | DSM501a GND pin |

^ description of similar sensor

https://github.com/opendata-stuttgart/meta/blob/master/files/ShinyeiPPD42NS_Deconstruction_TracyAllen.pdf

^ power supply

It really needs quiet power supply to get any readings which are not just noise.

{image: dsm501-schema.png}