Compare commits
3 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45c019a179 | ||
|
|
a6399c6884 | ||
|
|
94376be457 |
46
.github/ISSUE_TEMPLATE.md
vendored
|
|
@ -1,46 +0,0 @@
|
||||||
Thank you for opening an issue on an Adafruit Arduino library repository. To
|
|
||||||
improve the speed of resolution please review the following guidelines and
|
|
||||||
common troubleshooting steps below before creating the issue:
|
|
||||||
|
|
||||||
- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use
|
|
||||||
the forums at http://forums.adafruit.com to ask questions and troubleshoot why
|
|
||||||
something isn't working as expected. In many cases the problem is a common issue
|
|
||||||
that you will more quickly receive help from the forum community. GitHub issues
|
|
||||||
are meant for known defects in the code. If you don't know if there is a defect
|
|
||||||
in the code then start with troubleshooting on the forum first.
|
|
||||||
|
|
||||||
- **If following a tutorial or guide be sure you didn't miss a step.** Carefully
|
|
||||||
check all of the steps and commands to run have been followed. Consult the
|
|
||||||
forum if you're unsure or have questions about steps in a guide/tutorial.
|
|
||||||
|
|
||||||
- **For Arduino projects check these very common issues to ensure they don't apply**:
|
|
||||||
|
|
||||||
- For uploading sketches or communicating with the board make sure you're using
|
|
||||||
a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes
|
|
||||||
very hard to tell the difference between a data and charge cable! Try using the
|
|
||||||
cable with other devices or swapping to another cable to confirm it is not
|
|
||||||
the problem.
|
|
||||||
|
|
||||||
- **Be sure you are supplying adequate power to the board.** Check the specs of
|
|
||||||
your board and plug in an external power supply. In many cases just
|
|
||||||
plugging a board into your computer is not enough to power it and other
|
|
||||||
peripherals.
|
|
||||||
|
|
||||||
- **Double check all soldering joints and connections.** Flakey connections
|
|
||||||
cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints.
|
|
||||||
|
|
||||||
- **Ensure you are using an official Arduino or Adafruit board.** We can't
|
|
||||||
guarantee a clone board will have the same functionality and work as expected
|
|
||||||
with this code and don't support them.
|
|
||||||
|
|
||||||
If you're sure this issue is a defect in the code and checked the steps above
|
|
||||||
please fill in the following fields to provide enough troubleshooting information.
|
|
||||||
You may delete the guideline and text above to just leave the following details:
|
|
||||||
|
|
||||||
- Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE**
|
|
||||||
|
|
||||||
- Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO
|
|
||||||
VERSION HERE**
|
|
||||||
|
|
||||||
- List the steps to reproduce the problem below (if possible attach a sketch or
|
|
||||||
copy the sketch code in too): **LIST REPRO STEPS BELOW**
|
|
||||||
26
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
|
@ -1,26 +0,0 @@
|
||||||
Thank you for creating a pull request to contribute to Adafruit's GitHub code!
|
|
||||||
Before you open the request please review the following guidelines and tips to
|
|
||||||
help it be more easily integrated:
|
|
||||||
|
|
||||||
- **Describe the scope of your change--i.e. what the change does and what parts
|
|
||||||
of the code were modified.** This will help us understand any risks of integrating
|
|
||||||
the code.
|
|
||||||
|
|
||||||
- **Describe any known limitations with your change.** For example if the change
|
|
||||||
doesn't apply to a supported platform of the library please mention it.
|
|
||||||
|
|
||||||
- **Please run any tests or examples that can exercise your modified code.** We
|
|
||||||
strive to not break users of the code and running tests/examples helps with this
|
|
||||||
process.
|
|
||||||
|
|
||||||
Thank you again for contributing! We will try to test and integrate the change
|
|
||||||
as soon as we can, but be aware we have many GitHub repositories to manage and
|
|
||||||
can't immediately respond to every request. There is no need to bump or check in
|
|
||||||
on a pull request (it will clutter the discussion of the request).
|
|
||||||
|
|
||||||
Also don't be worried if the request is closed or not integrated--sometimes the
|
|
||||||
priorities of Adafruit's GitHub code (education, ease of use) might not match the
|
|
||||||
priorities of the pull request. Don't fret, the open source community thrives on
|
|
||||||
forks and GitHub makes it easy to keep your changes in a forked repo.
|
|
||||||
|
|
||||||
After reviewing the guidelines above you can delete this text from the pull request.
|
|
||||||
32
.github/workflows/githubci.yml
vendored
|
|
@ -1,32 +0,0 @@
|
||||||
name: Arduino Library CI
|
|
||||||
|
|
||||||
on: [pull_request, push, repository_dispatch]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/setup-python@v1
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
repository: adafruit/ci-arduino
|
|
||||||
path: ci
|
|
||||||
|
|
||||||
- name: pre-install
|
|
||||||
run: bash ci/actions_install.sh
|
|
||||||
|
|
||||||
- name: test platforms
|
|
||||||
run: python3 ci/build_platform.py main_platforms
|
|
||||||
|
|
||||||
- name: clang
|
|
||||||
run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r .
|
|
||||||
|
|
||||||
- name: doxygen
|
|
||||||
env:
|
|
||||||
GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }}
|
|
||||||
PRETTYNAME : "Adafruit CAN Arduino Library"
|
|
||||||
run: bash ci/doxy_gen_and_deploy.sh
|
|
||||||
1
.nojekyll
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
# Adafruit CAN Library
|
|
||||||
|
|
||||||
This is an Arduino library for the supporting boards with native CAN peripherals.
|
|
||||||
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
* Adafruit Feather M4 CAN Receiver Callback Example
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <CANSAME5x.h>
|
|
||||||
|
|
||||||
CANSAME5x CAN;
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(9600);
|
|
||||||
while (!Serial);
|
|
||||||
|
|
||||||
Serial.println("CAN Receiver Callback");
|
|
||||||
|
|
||||||
// start the CAN bus at 250 kbps
|
|
||||||
if (!CAN.begin(250E3)) {
|
|
||||||
Serial.println("Starting CAN failed!");
|
|
||||||
while (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// register the receive callback
|
|
||||||
CAN.onReceive(onReceive);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
void onReceive(int packetSize) {
|
|
||||||
// received a packet
|
|
||||||
Serial.print("Received ");
|
|
||||||
|
|
||||||
if (CAN.packetExtended()) {
|
|
||||||
Serial.print("extended ");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CAN.packetRtr()) {
|
|
||||||
// Remote transmission request, packet contains no data
|
|
||||||
Serial.print("RTR ");
|
|
||||||
}
|
|
||||||
|
|
||||||
Serial.print("packet with id 0x");
|
|
||||||
Serial.print(CAN.packetId(), HEX);
|
|
||||||
|
|
||||||
if (CAN.packetRtr()) {
|
|
||||||
Serial.print(" and requested length ");
|
|
||||||
Serial.println(CAN.packetDlc());
|
|
||||||
} else {
|
|
||||||
Serial.print(" and length ");
|
|
||||||
Serial.println(packetSize);
|
|
||||||
|
|
||||||
// only print packet data for non-RTR packets
|
|
||||||
while (CAN.available()) {
|
|
||||||
Serial.print((char)CAN.read());
|
|
||||||
}
|
|
||||||
Serial.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
Serial.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
/*
|
|
||||||
* Adafruit Feather M4 CAN Receiver Example
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <CANSAME5x.h>
|
|
||||||
|
|
||||||
CANSAME5x CAN;
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(9600);
|
|
||||||
while (!Serial);
|
|
||||||
|
|
||||||
Serial.println("CAN Receiver");
|
|
||||||
|
|
||||||
pinMode(PIN_CAN_STANDBY, OUTPUT);
|
|
||||||
digitalWrite(PIN_CAN_STANDBY, false); // turn off STANDBY
|
|
||||||
pinMode(PIN_CAN_BOOSTEN, OUTPUT);
|
|
||||||
digitalWrite(PIN_CAN_BOOSTEN, true); // turn on booster
|
|
||||||
|
|
||||||
// start the CAN bus at 250 kbps
|
|
||||||
if (!CAN.begin(250000)) {
|
|
||||||
Serial.println("Starting CAN failed!");
|
|
||||||
while (1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
// try to parse packet
|
|
||||||
int packetSize = CAN.parsePacket();
|
|
||||||
|
|
||||||
if (packetSize) {
|
|
||||||
// received a packet
|
|
||||||
Serial.print("Received ");
|
|
||||||
|
|
||||||
if (CAN.packetExtended()) {
|
|
||||||
Serial.print("extended ");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CAN.packetRtr()) {
|
|
||||||
// Remote transmission request, packet contains no data
|
|
||||||
Serial.print("RTR ");
|
|
||||||
}
|
|
||||||
|
|
||||||
Serial.print("packet with id 0x");
|
|
||||||
Serial.print(CAN.packetId(), HEX);
|
|
||||||
|
|
||||||
if (CAN.packetRtr()) {
|
|
||||||
Serial.print(" and requested length ");
|
|
||||||
Serial.println(CAN.packetDlc());
|
|
||||||
} else {
|
|
||||||
Serial.print(" and length ");
|
|
||||||
Serial.println(packetSize);
|
|
||||||
|
|
||||||
// only print packet data for non-RTR packets
|
|
||||||
while (CAN.available()) {
|
|
||||||
Serial.print((char)CAN.read());
|
|
||||||
}
|
|
||||||
Serial.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
Serial.println();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
/*
|
|
||||||
* Adafruit Feather M4 CAN Sender Example
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <CANSAME5x.h>
|
|
||||||
|
|
||||||
CANSAME5x CAN;
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(9600);
|
|
||||||
while (!Serial);
|
|
||||||
|
|
||||||
Serial.println("CAN Sender");
|
|
||||||
pinMode(PIN_CAN_STANDBY, OUTPUT);
|
|
||||||
digitalWrite(PIN_CAN_STANDBY, false); // turn off STANDBY
|
|
||||||
pinMode(PIN_CAN_BOOSTEN, OUTPUT);
|
|
||||||
digitalWrite(PIN_CAN_BOOSTEN, true); // turn on booster
|
|
||||||
|
|
||||||
// start the CAN bus at 250 kbps
|
|
||||||
if (!CAN.begin(250000)) {
|
|
||||||
Serial.println("Starting CAN failed!");
|
|
||||||
while (1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
// send packet: id is 11 bits, packet can contain up to 8 bytes of data
|
|
||||||
Serial.print("Sending packet ... ");
|
|
||||||
|
|
||||||
CAN.beginPacket(0x12);
|
|
||||||
CAN.write('h');
|
|
||||||
CAN.write('e');
|
|
||||||
CAN.write('l');
|
|
||||||
CAN.write('l');
|
|
||||||
CAN.write('o');
|
|
||||||
CAN.endPacket();
|
|
||||||
|
|
||||||
Serial.println("done");
|
|
||||||
|
|
||||||
delay(1000);
|
|
||||||
|
|
||||||
// send extended packet: id is 29 bits, packet can contain up to 8 bytes of data
|
|
||||||
Serial.print("Sending extended packet ... ");
|
|
||||||
|
|
||||||
CAN.beginExtendedPacket(0xabcdef);
|
|
||||||
CAN.write('w');
|
|
||||||
CAN.write('o');
|
|
||||||
CAN.write('r');
|
|
||||||
CAN.write('l');
|
|
||||||
CAN.write('d');
|
|
||||||
CAN.endPacket();
|
|
||||||
|
|
||||||
Serial.println("done");
|
|
||||||
|
|
||||||
delay(1000);
|
|
||||||
}
|
|
||||||
BIN
html/bc_s.png
Normal file
|
After Width: | Height: | Size: 676 B |
BIN
html/bdwn.png
Normal file
|
After Width: | Height: | Size: 147 B |
BIN
html/closed.png
Normal file
|
After Width: | Height: | Size: 132 B |
BIN
html/doc.png
Normal file
|
After Width: | Height: | Size: 746 B |
1596
html/doxygen.css
Normal file
BIN
html/doxygen.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
97
html/dynsections.js
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
function toggleVisibility(linkObj)
|
||||||
|
{
|
||||||
|
var base = $(linkObj).attr('id');
|
||||||
|
var summary = $('#'+base+'-summary');
|
||||||
|
var content = $('#'+base+'-content');
|
||||||
|
var trigger = $('#'+base+'-trigger');
|
||||||
|
var src=$(trigger).attr('src');
|
||||||
|
if (content.is(':visible')===true) {
|
||||||
|
content.hide();
|
||||||
|
summary.show();
|
||||||
|
$(linkObj).addClass('closed').removeClass('opened');
|
||||||
|
$(trigger).attr('src',src.substring(0,src.length-8)+'closed.png');
|
||||||
|
} else {
|
||||||
|
content.show();
|
||||||
|
summary.hide();
|
||||||
|
$(linkObj).removeClass('closed').addClass('opened');
|
||||||
|
$(trigger).attr('src',src.substring(0,src.length-10)+'open.png');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateStripes()
|
||||||
|
{
|
||||||
|
$('table.directory tr').
|
||||||
|
removeClass('even').filter(':visible:even').addClass('even');
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleLevel(level)
|
||||||
|
{
|
||||||
|
$('table.directory tr').each(function() {
|
||||||
|
var l = this.id.split('_').length-1;
|
||||||
|
var i = $('#img'+this.id.substring(3));
|
||||||
|
var a = $('#arr'+this.id.substring(3));
|
||||||
|
if (l<level+1) {
|
||||||
|
i.removeClass('iconfopen iconfclosed').addClass('iconfopen');
|
||||||
|
a.html('▼');
|
||||||
|
$(this).show();
|
||||||
|
} else if (l==level+1) {
|
||||||
|
i.removeClass('iconfclosed iconfopen').addClass('iconfclosed');
|
||||||
|
a.html('►');
|
||||||
|
$(this).show();
|
||||||
|
} else {
|
||||||
|
$(this).hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
updateStripes();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleFolder(id)
|
||||||
|
{
|
||||||
|
// the clicked row
|
||||||
|
var currentRow = $('#row_'+id);
|
||||||
|
|
||||||
|
// all rows after the clicked row
|
||||||
|
var rows = currentRow.nextAll("tr");
|
||||||
|
|
||||||
|
var re = new RegExp('^row_'+id+'\\d+_$', "i"); //only one sub
|
||||||
|
|
||||||
|
// only match elements AFTER this one (can't hide elements before)
|
||||||
|
var childRows = rows.filter(function() { return this.id.match(re); });
|
||||||
|
|
||||||
|
// first row is visible we are HIDING
|
||||||
|
if (childRows.filter(':first').is(':visible')===true) {
|
||||||
|
// replace down arrow by right arrow for current row
|
||||||
|
var currentRowSpans = currentRow.find("span");
|
||||||
|
currentRowSpans.filter(".iconfopen").removeClass("iconfopen").addClass("iconfclosed");
|
||||||
|
currentRowSpans.filter(".arrow").html('►');
|
||||||
|
rows.filter("[id^=row_"+id+"]").hide(); // hide all children
|
||||||
|
} else { // we are SHOWING
|
||||||
|
// replace right arrow by down arrow for current row
|
||||||
|
var currentRowSpans = currentRow.find("span");
|
||||||
|
currentRowSpans.filter(".iconfclosed").removeClass("iconfclosed").addClass("iconfopen");
|
||||||
|
currentRowSpans.filter(".arrow").html('▼');
|
||||||
|
// replace down arrows by right arrows for child rows
|
||||||
|
var childRowsSpans = childRows.find("span");
|
||||||
|
childRowsSpans.filter(".iconfopen").removeClass("iconfopen").addClass("iconfclosed");
|
||||||
|
childRowsSpans.filter(".arrow").html('►');
|
||||||
|
childRows.show(); //show all children
|
||||||
|
}
|
||||||
|
updateStripes();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function toggleInherit(id)
|
||||||
|
{
|
||||||
|
var rows = $('tr.inherit.'+id);
|
||||||
|
var img = $('tr.inherit_header.'+id+' img');
|
||||||
|
var src = $(img).attr('src');
|
||||||
|
if (rows.filter(':first').is(':visible')===true) {
|
||||||
|
rows.css('display','none');
|
||||||
|
$(img).attr('src',src.substring(0,src.length-8)+'closed.png');
|
||||||
|
} else {
|
||||||
|
rows.css('display','table-row'); // using show() causes jump in firefox
|
||||||
|
$(img).attr('src',src.substring(0,src.length-10)+'open.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BIN
html/folderclosed.png
Normal file
|
After Width: | Height: | Size: 616 B |
BIN
html/folderopen.png
Normal file
|
After Width: | Height: | Size: 597 B |
73
html/index.html
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||||
|
<meta name="generator" content="Doxygen 1.8.13"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
|
<title>Adafruit CAN Arduino Library: Main Page</title>
|
||||||
|
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
||||||
|
<script type="text/javascript" src="jquery.js"></script>
|
||||||
|
<script type="text/javascript" src="dynsections.js"></script>
|
||||||
|
<link href="search/search.css" rel="stylesheet" type="text/css"/>
|
||||||
|
<script type="text/javascript" src="search/searchdata.js"></script>
|
||||||
|
<script type="text/javascript" src="search/search.js"></script>
|
||||||
|
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||||
|
<div id="titlearea">
|
||||||
|
<table cellspacing="0" cellpadding="0">
|
||||||
|
<tbody>
|
||||||
|
<tr style="height: 56px;">
|
||||||
|
<td id="projectalign" style="padding-left: 0.5em;">
|
||||||
|
<div id="projectname">Adafruit CAN Arduino Library
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!-- end header part -->
|
||||||
|
<!-- Generated by Doxygen 1.8.13 -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript" src="menudata.js"></script>
|
||||||
|
<script type="text/javascript" src="menu.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(function() {
|
||||||
|
initMenu('',true,false,'search.php','Search');
|
||||||
|
$(document).ready(function() { init_search(); });
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<div id="main-nav"></div>
|
||||||
|
</div><!-- top -->
|
||||||
|
<!-- window showing the filter options -->
|
||||||
|
<div id="MSearchSelectWindow"
|
||||||
|
onmouseover="return searchBox.OnSearchSelectShow()"
|
||||||
|
onmouseout="return searchBox.OnSearchSelectHide()"
|
||||||
|
onkeydown="return searchBox.OnSearchSelectKey(event)">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- iframe showing the search results (closed by default) -->
|
||||||
|
<div id="MSearchResultsWindow">
|
||||||
|
<iframe src="javascript:void(0)" frameborder="0"
|
||||||
|
name="MSearchResults" id="MSearchResults">
|
||||||
|
</iframe>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="header">
|
||||||
|
<div class="headertitle">
|
||||||
|
<div class="title">Adafruit CAN Arduino Library Documentation</div> </div>
|
||||||
|
</div><!--header-->
|
||||||
|
<div class="contents">
|
||||||
|
</div><!-- contents -->
|
||||||
|
<!-- start footer part -->
|
||||||
|
<hr class="footer"/><address class="footer"><small>
|
||||||
|
Generated by  <a href="http://www.doxygen.org/index.html">
|
||||||
|
<img class="footer" src="doxygen.png" alt="doxygen"/>
|
||||||
|
</a> 1.8.13
|
||||||
|
</small></address>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
html/jquery.js
vendored
Normal file
26
html/menu.js
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
function initMenu(relPath,searchEnabled,serverSide,searchPage,search) {
|
||||||
|
function makeTree(data,relPath) {
|
||||||
|
var result='';
|
||||||
|
if ('children' in data) {
|
||||||
|
result+='<ul>';
|
||||||
|
for (var i in data.children) {
|
||||||
|
result+='<li><a href="'+relPath+data.children[i].url+'">'+
|
||||||
|
data.children[i].text+'</a>'+
|
||||||
|
makeTree(data.children[i],relPath)+'</li>';
|
||||||
|
}
|
||||||
|
result+='</ul>';
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#main-nav').append(makeTree(menudata,relPath));
|
||||||
|
$('#main-nav').children(':first').addClass('sm sm-dox').attr('id','main-menu');
|
||||||
|
if (searchEnabled) {
|
||||||
|
if (serverSide) {
|
||||||
|
$('#main-menu').append('<li style="float:right"><div id="MSearchBox" class="MSearchBoxInactive"><div class="left"><form id="FSearchBox" action="'+searchPage+'" method="get"><img id="MSearchSelect" src="'+relPath+'search/mag.png" alt=""/><input type="text" id="MSearchField" name="query" value="'+search+'" size="20" accesskey="S" onfocus="searchBox.OnSearchFieldFocus(true)" onblur="searchBox.OnSearchFieldFocus(false)"></form></div><div class="right"></div></div></li>');
|
||||||
|
} else {
|
||||||
|
$('#main-menu').append('<li style="float:right"><div id="MSearchBox" class="MSearchBoxInactive"><span class="left"><img id="MSearchSelect" src="'+relPath+'search/mag_sel.png" onmouseover="return searchBox.OnSearchSelectShow()" onmouseout="return searchBox.OnSearchSelectHide()" alt=""/><input type="text" id="MSearchField" value="'+search+'" accesskey="S" onfocus="searchBox.OnSearchFieldFocus(true)" onblur="searchBox.OnSearchFieldFocus(false)" onkeyup="searchBox.OnSearchFieldChange(event)"/></span><span class="right"><a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="'+relPath+'search/close.png" alt=""/></a></span></div></li>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('#main-menu').smartmenus();
|
||||||
|
}
|
||||||
2
html/menudata.js
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
var menudata={children:[
|
||||||
|
{text:"Main Page",url:"index.html"}]}
|
||||||
BIN
html/nav_f.png
Normal file
|
After Width: | Height: | Size: 153 B |
BIN
html/nav_g.png
Normal file
|
After Width: | Height: | Size: 95 B |
BIN
html/nav_h.png
Normal file
|
After Width: | Height: | Size: 98 B |
BIN
html/open.png
Normal file
|
After Width: | Height: | Size: 123 B |
BIN
html/search/close.png
Normal file
|
After Width: | Height: | Size: 273 B |
BIN
html/search/mag_sel.png
Normal file
|
After Width: | Height: | Size: 563 B |
12
html/search/nomatches.html
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html><head><title></title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||||
|
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||||
|
<script type="text/javascript" src="search.js"></script>
|
||||||
|
</head>
|
||||||
|
<body class="SRPage">
|
||||||
|
<div id="SRIndex">
|
||||||
|
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
271
html/search/search.css
Normal file
|
|
@ -0,0 +1,271 @@
|
||||||
|
/*---------------- Search Box */
|
||||||
|
|
||||||
|
#FSearchBox {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#MSearchBox {
|
||||||
|
white-space : nowrap;
|
||||||
|
float: none;
|
||||||
|
margin-top: 8px;
|
||||||
|
right: 0px;
|
||||||
|
width: 170px;
|
||||||
|
height: 24px;
|
||||||
|
z-index: 102;
|
||||||
|
}
|
||||||
|
|
||||||
|
#MSearchBox .left
|
||||||
|
{
|
||||||
|
display:block;
|
||||||
|
position:absolute;
|
||||||
|
left:10px;
|
||||||
|
width:20px;
|
||||||
|
height:19px;
|
||||||
|
background:url('search_l.png') no-repeat;
|
||||||
|
background-position:right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#MSearchSelect {
|
||||||
|
display:block;
|
||||||
|
position:absolute;
|
||||||
|
width:20px;
|
||||||
|
height:19px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left #MSearchSelect {
|
||||||
|
left:4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right #MSearchSelect {
|
||||||
|
right:5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#MSearchField {
|
||||||
|
display:block;
|
||||||
|
position:absolute;
|
||||||
|
height:19px;
|
||||||
|
background:url('search_m.png') repeat-x;
|
||||||
|
border:none;
|
||||||
|
width:115px;
|
||||||
|
margin-left:20px;
|
||||||
|
padding-left:4px;
|
||||||
|
color: #909090;
|
||||||
|
outline: none;
|
||||||
|
font: 9pt Arial, Verdana, sans-serif;
|
||||||
|
-webkit-border-radius: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#FSearchBox #MSearchField {
|
||||||
|
margin-left:15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#MSearchBox .right {
|
||||||
|
display:block;
|
||||||
|
position:absolute;
|
||||||
|
right:10px;
|
||||||
|
top:8px;
|
||||||
|
width:20px;
|
||||||
|
height:19px;
|
||||||
|
background:url('search_r.png') no-repeat;
|
||||||
|
background-position:left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#MSearchClose {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
background : none;
|
||||||
|
border: none;
|
||||||
|
margin: 0px 4px 0px 0px;
|
||||||
|
padding: 0px 0px;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left #MSearchClose {
|
||||||
|
left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right #MSearchClose {
|
||||||
|
right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MSearchBoxActive #MSearchField {
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------- Search filter selection */
|
||||||
|
|
||||||
|
#MSearchSelectWindow {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
left: 0; top: 0;
|
||||||
|
border: 1px solid #90A5CE;
|
||||||
|
background-color: #F9FAFC;
|
||||||
|
z-index: 10001;
|
||||||
|
padding-top: 4px;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
-moz-border-radius: 4px;
|
||||||
|
-webkit-border-top-left-radius: 4px;
|
||||||
|
-webkit-border-top-right-radius: 4px;
|
||||||
|
-webkit-border-bottom-left-radius: 4px;
|
||||||
|
-webkit-border-bottom-right-radius: 4px;
|
||||||
|
-webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.SelectItem {
|
||||||
|
font: 8pt Arial, Verdana, sans-serif;
|
||||||
|
padding-left: 2px;
|
||||||
|
padding-right: 12px;
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.SelectionMark {
|
||||||
|
margin-right: 4px;
|
||||||
|
font-family: monospace;
|
||||||
|
outline-style: none;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.SelectItem {
|
||||||
|
display: block;
|
||||||
|
outline-style: none;
|
||||||
|
color: #000000;
|
||||||
|
text-decoration: none;
|
||||||
|
padding-left: 6px;
|
||||||
|
padding-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.SelectItem:focus,
|
||||||
|
a.SelectItem:active {
|
||||||
|
color: #000000;
|
||||||
|
outline-style: none;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.SelectItem:hover {
|
||||||
|
color: #FFFFFF;
|
||||||
|
background-color: #3D578C;
|
||||||
|
outline-style: none;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------- Search results window */
|
||||||
|
|
||||||
|
iframe#MSearchResults {
|
||||||
|
width: 60ex;
|
||||||
|
height: 15em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#MSearchResultsWindow {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
left: 0; top: 0;
|
||||||
|
border: 1px solid #000;
|
||||||
|
background-color: #EEF1F7;
|
||||||
|
z-index:10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
#SRIndex {
|
||||||
|
clear:both;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SREntry {
|
||||||
|
font-size: 10pt;
|
||||||
|
padding-left: 1ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SRPage .SREntry {
|
||||||
|
font-size: 8pt;
|
||||||
|
padding: 1px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.SRPage {
|
||||||
|
margin: 5px 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SRChildren {
|
||||||
|
padding-left: 3ex; padding-bottom: .5em
|
||||||
|
}
|
||||||
|
|
||||||
|
.SRPage .SRChildren {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SRSymbol {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #425E97;
|
||||||
|
font-family: Arial, Verdana, sans-serif;
|
||||||
|
text-decoration: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.SRScope {
|
||||||
|
display: block;
|
||||||
|
color: #425E97;
|
||||||
|
font-family: Arial, Verdana, sans-serif;
|
||||||
|
text-decoration: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.SRSymbol:focus, a.SRSymbol:active,
|
||||||
|
a.SRScope:focus, a.SRScope:active {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.SRScope {
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SRPage .SRStatus {
|
||||||
|
padding: 2px 5px;
|
||||||
|
font-size: 8pt;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SRResult {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
DIV.searchresults {
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------- External search page results */
|
||||||
|
|
||||||
|
.searchresult {
|
||||||
|
background-color: #F0F3F8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pages b {
|
||||||
|
color: white;
|
||||||
|
padding: 5px 5px 3px 5px;
|
||||||
|
background-image: url("../tab_a.png");
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
text-shadow: 0 1px 1px #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pages {
|
||||||
|
line-height: 17px;
|
||||||
|
margin-left: 4px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hl {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#searchresults {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchpages {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
791
html/search/search.js
Normal file
|
|
@ -0,0 +1,791 @@
|
||||||
|
function convertToId(search)
|
||||||
|
{
|
||||||
|
var result = '';
|
||||||
|
for (i=0;i<search.length;i++)
|
||||||
|
{
|
||||||
|
var c = search.charAt(i);
|
||||||
|
var cn = c.charCodeAt(0);
|
||||||
|
if (c.match(/[a-z0-9\u0080-\uFFFF]/))
|
||||||
|
{
|
||||||
|
result+=c;
|
||||||
|
}
|
||||||
|
else if (cn<16)
|
||||||
|
{
|
||||||
|
result+="_0"+cn.toString(16);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result+="_"+cn.toString(16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getXPos(item)
|
||||||
|
{
|
||||||
|
var x = 0;
|
||||||
|
if (item.offsetWidth)
|
||||||
|
{
|
||||||
|
while (item && item!=document.body)
|
||||||
|
{
|
||||||
|
x += item.offsetLeft;
|
||||||
|
item = item.offsetParent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getYPos(item)
|
||||||
|
{
|
||||||
|
var y = 0;
|
||||||
|
if (item.offsetWidth)
|
||||||
|
{
|
||||||
|
while (item && item!=document.body)
|
||||||
|
{
|
||||||
|
y += item.offsetTop;
|
||||||
|
item = item.offsetParent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A class handling everything associated with the search panel.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
name - The name of the global variable that will be
|
||||||
|
storing this instance. Is needed to be able to set timeouts.
|
||||||
|
resultPath - path to use for external files
|
||||||
|
*/
|
||||||
|
function SearchBox(name, resultsPath, inFrame, label)
|
||||||
|
{
|
||||||
|
if (!name || !resultsPath) { alert("Missing parameters to SearchBox."); }
|
||||||
|
|
||||||
|
// ---------- Instance variables
|
||||||
|
this.name = name;
|
||||||
|
this.resultsPath = resultsPath;
|
||||||
|
this.keyTimeout = 0;
|
||||||
|
this.keyTimeoutLength = 500;
|
||||||
|
this.closeSelectionTimeout = 300;
|
||||||
|
this.lastSearchValue = "";
|
||||||
|
this.lastResultsPage = "";
|
||||||
|
this.hideTimeout = 0;
|
||||||
|
this.searchIndex = 0;
|
||||||
|
this.searchActive = false;
|
||||||
|
this.insideFrame = inFrame;
|
||||||
|
this.searchLabel = label;
|
||||||
|
|
||||||
|
// ----------- DOM Elements
|
||||||
|
|
||||||
|
this.DOMSearchField = function()
|
||||||
|
{ return document.getElementById("MSearchField"); }
|
||||||
|
|
||||||
|
this.DOMSearchSelect = function()
|
||||||
|
{ return document.getElementById("MSearchSelect"); }
|
||||||
|
|
||||||
|
this.DOMSearchSelectWindow = function()
|
||||||
|
{ return document.getElementById("MSearchSelectWindow"); }
|
||||||
|
|
||||||
|
this.DOMPopupSearchResults = function()
|
||||||
|
{ return document.getElementById("MSearchResults"); }
|
||||||
|
|
||||||
|
this.DOMPopupSearchResultsWindow = function()
|
||||||
|
{ return document.getElementById("MSearchResultsWindow"); }
|
||||||
|
|
||||||
|
this.DOMSearchClose = function()
|
||||||
|
{ return document.getElementById("MSearchClose"); }
|
||||||
|
|
||||||
|
this.DOMSearchBox = function()
|
||||||
|
{ return document.getElementById("MSearchBox"); }
|
||||||
|
|
||||||
|
// ------------ Event Handlers
|
||||||
|
|
||||||
|
// Called when focus is added or removed from the search field.
|
||||||
|
this.OnSearchFieldFocus = function(isActive)
|
||||||
|
{
|
||||||
|
this.Activate(isActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.OnSearchSelectShow = function()
|
||||||
|
{
|
||||||
|
var searchSelectWindow = this.DOMSearchSelectWindow();
|
||||||
|
var searchField = this.DOMSearchSelect();
|
||||||
|
|
||||||
|
if (this.insideFrame)
|
||||||
|
{
|
||||||
|
var left = getXPos(searchField);
|
||||||
|
var top = getYPos(searchField);
|
||||||
|
left += searchField.offsetWidth + 6;
|
||||||
|
top += searchField.offsetHeight;
|
||||||
|
|
||||||
|
// show search selection popup
|
||||||
|
searchSelectWindow.style.display='block';
|
||||||
|
left -= searchSelectWindow.offsetWidth;
|
||||||
|
searchSelectWindow.style.left = left + 'px';
|
||||||
|
searchSelectWindow.style.top = top + 'px';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var left = getXPos(searchField);
|
||||||
|
var top = getYPos(searchField);
|
||||||
|
top += searchField.offsetHeight;
|
||||||
|
|
||||||
|
// show search selection popup
|
||||||
|
searchSelectWindow.style.display='block';
|
||||||
|
searchSelectWindow.style.left = left + 'px';
|
||||||
|
searchSelectWindow.style.top = top + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop selection hide timer
|
||||||
|
if (this.hideTimeout)
|
||||||
|
{
|
||||||
|
clearTimeout(this.hideTimeout);
|
||||||
|
this.hideTimeout=0;
|
||||||
|
}
|
||||||
|
return false; // to avoid "image drag" default event
|
||||||
|
}
|
||||||
|
|
||||||
|
this.OnSearchSelectHide = function()
|
||||||
|
{
|
||||||
|
this.hideTimeout = setTimeout(this.name +".CloseSelectionWindow()",
|
||||||
|
this.closeSelectionTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when the content of the search field is changed.
|
||||||
|
this.OnSearchFieldChange = function(evt)
|
||||||
|
{
|
||||||
|
if (this.keyTimeout) // kill running timer
|
||||||
|
{
|
||||||
|
clearTimeout(this.keyTimeout);
|
||||||
|
this.keyTimeout = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var e = (evt) ? evt : window.event; // for IE
|
||||||
|
if (e.keyCode==40 || e.keyCode==13)
|
||||||
|
{
|
||||||
|
if (e.shiftKey==1)
|
||||||
|
{
|
||||||
|
this.OnSearchSelectShow();
|
||||||
|
var win=this.DOMSearchSelectWindow();
|
||||||
|
for (i=0;i<win.childNodes.length;i++)
|
||||||
|
{
|
||||||
|
var child = win.childNodes[i]; // get span within a
|
||||||
|
if (child.className=='SelectItem')
|
||||||
|
{
|
||||||
|
child.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (window.frames.MSearchResults.searchResults)
|
||||||
|
{
|
||||||
|
var elem = window.frames.MSearchResults.searchResults.NavNext(0);
|
||||||
|
if (elem) elem.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (e.keyCode==27) // Escape out of the search field
|
||||||
|
{
|
||||||
|
this.DOMSearchField().blur();
|
||||||
|
this.DOMPopupSearchResultsWindow().style.display = 'none';
|
||||||
|
this.DOMSearchClose().style.display = 'none';
|
||||||
|
this.lastSearchValue = '';
|
||||||
|
this.Activate(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// strip whitespaces
|
||||||
|
var searchValue = this.DOMSearchField().value.replace(/ +/g, "");
|
||||||
|
|
||||||
|
if (searchValue != this.lastSearchValue) // search value has changed
|
||||||
|
{
|
||||||
|
if (searchValue != "") // non-empty search
|
||||||
|
{
|
||||||
|
// set timer for search update
|
||||||
|
this.keyTimeout = setTimeout(this.name + '.Search()',
|
||||||
|
this.keyTimeoutLength);
|
||||||
|
}
|
||||||
|
else // empty search field
|
||||||
|
{
|
||||||
|
this.DOMPopupSearchResultsWindow().style.display = 'none';
|
||||||
|
this.DOMSearchClose().style.display = 'none';
|
||||||
|
this.lastSearchValue = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.SelectItemCount = function(id)
|
||||||
|
{
|
||||||
|
var count=0;
|
||||||
|
var win=this.DOMSearchSelectWindow();
|
||||||
|
for (i=0;i<win.childNodes.length;i++)
|
||||||
|
{
|
||||||
|
var child = win.childNodes[i]; // get span within a
|
||||||
|
if (child.className=='SelectItem')
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.SelectItemSet = function(id)
|
||||||
|
{
|
||||||
|
var i,j=0;
|
||||||
|
var win=this.DOMSearchSelectWindow();
|
||||||
|
for (i=0;i<win.childNodes.length;i++)
|
||||||
|
{
|
||||||
|
var child = win.childNodes[i]; // get span within a
|
||||||
|
if (child.className=='SelectItem')
|
||||||
|
{
|
||||||
|
var node = child.firstChild;
|
||||||
|
if (j==id)
|
||||||
|
{
|
||||||
|
node.innerHTML='•';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node.innerHTML=' ';
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when an search filter selection is made.
|
||||||
|
// set item with index id as the active item
|
||||||
|
this.OnSelectItem = function(id)
|
||||||
|
{
|
||||||
|
this.searchIndex = id;
|
||||||
|
this.SelectItemSet(id);
|
||||||
|
var searchValue = this.DOMSearchField().value.replace(/ +/g, "");
|
||||||
|
if (searchValue!="" && this.searchActive) // something was found -> do a search
|
||||||
|
{
|
||||||
|
this.Search();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.OnSearchSelectKey = function(evt)
|
||||||
|
{
|
||||||
|
var e = (evt) ? evt : window.event; // for IE
|
||||||
|
if (e.keyCode==40 && this.searchIndex<this.SelectItemCount()) // Down
|
||||||
|
{
|
||||||
|
this.searchIndex++;
|
||||||
|
this.OnSelectItem(this.searchIndex);
|
||||||
|
}
|
||||||
|
else if (e.keyCode==38 && this.searchIndex>0) // Up
|
||||||
|
{
|
||||||
|
this.searchIndex--;
|
||||||
|
this.OnSelectItem(this.searchIndex);
|
||||||
|
}
|
||||||
|
else if (e.keyCode==13 || e.keyCode==27)
|
||||||
|
{
|
||||||
|
this.OnSelectItem(this.searchIndex);
|
||||||
|
this.CloseSelectionWindow();
|
||||||
|
this.DOMSearchField().focus();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------- Actions
|
||||||
|
|
||||||
|
// Closes the results window.
|
||||||
|
this.CloseResultsWindow = function()
|
||||||
|
{
|
||||||
|
this.DOMPopupSearchResultsWindow().style.display = 'none';
|
||||||
|
this.DOMSearchClose().style.display = 'none';
|
||||||
|
this.Activate(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.CloseSelectionWindow = function()
|
||||||
|
{
|
||||||
|
this.DOMSearchSelectWindow().style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Performs a search.
|
||||||
|
this.Search = function()
|
||||||
|
{
|
||||||
|
this.keyTimeout = 0;
|
||||||
|
|
||||||
|
// strip leading whitespace
|
||||||
|
var searchValue = this.DOMSearchField().value.replace(/^ +/, "");
|
||||||
|
|
||||||
|
var code = searchValue.toLowerCase().charCodeAt(0);
|
||||||
|
var idxChar = searchValue.substr(0, 1).toLowerCase();
|
||||||
|
if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) // surrogate pair
|
||||||
|
{
|
||||||
|
idxChar = searchValue.substr(0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultsPage;
|
||||||
|
var resultsPageWithSearch;
|
||||||
|
var hasResultsPage;
|
||||||
|
|
||||||
|
var idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar);
|
||||||
|
if (idx!=-1)
|
||||||
|
{
|
||||||
|
var hexCode=idx.toString(16);
|
||||||
|
resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html';
|
||||||
|
resultsPageWithSearch = resultsPage+'?'+escape(searchValue);
|
||||||
|
hasResultsPage = true;
|
||||||
|
}
|
||||||
|
else // nothing available for this search term
|
||||||
|
{
|
||||||
|
resultsPage = this.resultsPath + '/nomatches.html';
|
||||||
|
resultsPageWithSearch = resultsPage;
|
||||||
|
hasResultsPage = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.frames.MSearchResults.location = resultsPageWithSearch;
|
||||||
|
var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow();
|
||||||
|
|
||||||
|
if (domPopupSearchResultsWindow.style.display!='block')
|
||||||
|
{
|
||||||
|
var domSearchBox = this.DOMSearchBox();
|
||||||
|
this.DOMSearchClose().style.display = 'inline';
|
||||||
|
if (this.insideFrame)
|
||||||
|
{
|
||||||
|
var domPopupSearchResults = this.DOMPopupSearchResults();
|
||||||
|
domPopupSearchResultsWindow.style.position = 'relative';
|
||||||
|
domPopupSearchResultsWindow.style.display = 'block';
|
||||||
|
var width = document.body.clientWidth - 8; // the -8 is for IE :-(
|
||||||
|
domPopupSearchResultsWindow.style.width = width + 'px';
|
||||||
|
domPopupSearchResults.style.width = width + 'px';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var domPopupSearchResults = this.DOMPopupSearchResults();
|
||||||
|
var left = getXPos(domSearchBox) + 150; // domSearchBox.offsetWidth;
|
||||||
|
var top = getYPos(domSearchBox) + 20; // domSearchBox.offsetHeight + 1;
|
||||||
|
domPopupSearchResultsWindow.style.display = 'block';
|
||||||
|
left -= domPopupSearchResults.offsetWidth;
|
||||||
|
domPopupSearchResultsWindow.style.top = top + 'px';
|
||||||
|
domPopupSearchResultsWindow.style.left = left + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastSearchValue = searchValue;
|
||||||
|
this.lastResultsPage = resultsPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------- Activation Functions
|
||||||
|
|
||||||
|
// Activates or deactivates the search panel, resetting things to
|
||||||
|
// their default values if necessary.
|
||||||
|
this.Activate = function(isActive)
|
||||||
|
{
|
||||||
|
if (isActive || // open it
|
||||||
|
this.DOMPopupSearchResultsWindow().style.display == 'block'
|
||||||
|
)
|
||||||
|
{
|
||||||
|
this.DOMSearchBox().className = 'MSearchBoxActive';
|
||||||
|
|
||||||
|
var searchField = this.DOMSearchField();
|
||||||
|
|
||||||
|
if (searchField.value == this.searchLabel) // clear "Search" term upon entry
|
||||||
|
{
|
||||||
|
searchField.value = '';
|
||||||
|
this.searchActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!isActive) // directly remove the panel
|
||||||
|
{
|
||||||
|
this.DOMSearchBox().className = 'MSearchBoxInactive';
|
||||||
|
this.DOMSearchField().value = this.searchLabel;
|
||||||
|
this.searchActive = false;
|
||||||
|
this.lastSearchValue = ''
|
||||||
|
this.lastResultsPage = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
// The class that handles everything on the search results page.
|
||||||
|
function SearchResults(name)
|
||||||
|
{
|
||||||
|
// The number of matches from the last run of <Search()>.
|
||||||
|
this.lastMatchCount = 0;
|
||||||
|
this.lastKey = 0;
|
||||||
|
this.repeatOn = false;
|
||||||
|
|
||||||
|
// Toggles the visibility of the passed element ID.
|
||||||
|
this.FindChildElement = function(id)
|
||||||
|
{
|
||||||
|
var parentElement = document.getElementById(id);
|
||||||
|
var element = parentElement.firstChild;
|
||||||
|
|
||||||
|
while (element && element!=parentElement)
|
||||||
|
{
|
||||||
|
if (element.nodeName == 'DIV' && element.className == 'SRChildren')
|
||||||
|
{
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.nodeName == 'DIV' && element.hasChildNodes())
|
||||||
|
{
|
||||||
|
element = element.firstChild;
|
||||||
|
}
|
||||||
|
else if (element.nextSibling)
|
||||||
|
{
|
||||||
|
element = element.nextSibling;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
element = element.parentNode;
|
||||||
|
}
|
||||||
|
while (element && element!=parentElement && !element.nextSibling);
|
||||||
|
|
||||||
|
if (element && element!=parentElement)
|
||||||
|
{
|
||||||
|
element = element.nextSibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Toggle = function(id)
|
||||||
|
{
|
||||||
|
var element = this.FindChildElement(id);
|
||||||
|
if (element)
|
||||||
|
{
|
||||||
|
if (element.style.display == 'block')
|
||||||
|
{
|
||||||
|
element.style.display = 'none';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
element.style.display = 'block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Searches for the passed string. If there is no parameter,
|
||||||
|
// it takes it from the URL query.
|
||||||
|
//
|
||||||
|
// Always returns true, since other documents may try to call it
|
||||||
|
// and that may or may not be possible.
|
||||||
|
this.Search = function(search)
|
||||||
|
{
|
||||||
|
if (!search) // get search word from URL
|
||||||
|
{
|
||||||
|
search = window.location.search;
|
||||||
|
search = search.substring(1); // Remove the leading '?'
|
||||||
|
search = unescape(search);
|
||||||
|
}
|
||||||
|
|
||||||
|
search = search.replace(/^ +/, ""); // strip leading spaces
|
||||||
|
search = search.replace(/ +$/, ""); // strip trailing spaces
|
||||||
|
search = search.toLowerCase();
|
||||||
|
search = convertToId(search);
|
||||||
|
|
||||||
|
var resultRows = document.getElementsByTagName("div");
|
||||||
|
var matches = 0;
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
while (i < resultRows.length)
|
||||||
|
{
|
||||||
|
var row = resultRows.item(i);
|
||||||
|
if (row.className == "SRResult")
|
||||||
|
{
|
||||||
|
var rowMatchName = row.id.toLowerCase();
|
||||||
|
rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_'
|
||||||
|
|
||||||
|
if (search.length<=rowMatchName.length &&
|
||||||
|
rowMatchName.substr(0, search.length)==search)
|
||||||
|
{
|
||||||
|
row.style.display = 'block';
|
||||||
|
matches++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
row.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
document.getElementById("Searching").style.display='none';
|
||||||
|
if (matches == 0) // no results
|
||||||
|
{
|
||||||
|
document.getElementById("NoMatches").style.display='block';
|
||||||
|
}
|
||||||
|
else // at least one result
|
||||||
|
{
|
||||||
|
document.getElementById("NoMatches").style.display='none';
|
||||||
|
}
|
||||||
|
this.lastMatchCount = matches;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the first item with index index or higher that is visible
|
||||||
|
this.NavNext = function(index)
|
||||||
|
{
|
||||||
|
var focusItem;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
var focusName = 'Item'+index;
|
||||||
|
focusItem = document.getElementById(focusName);
|
||||||
|
if (focusItem && focusItem.parentNode.parentNode.style.display=='block')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (!focusItem) // last element
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
focusItem=null;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return focusItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.NavPrev = function(index)
|
||||||
|
{
|
||||||
|
var focusItem;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
var focusName = 'Item'+index;
|
||||||
|
focusItem = document.getElementById(focusName);
|
||||||
|
if (focusItem && focusItem.parentNode.parentNode.style.display=='block')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (!focusItem) // last element
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
focusItem=null;
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
return focusItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ProcessKeys = function(e)
|
||||||
|
{
|
||||||
|
if (e.type == "keydown")
|
||||||
|
{
|
||||||
|
this.repeatOn = false;
|
||||||
|
this.lastKey = e.keyCode;
|
||||||
|
}
|
||||||
|
else if (e.type == "keypress")
|
||||||
|
{
|
||||||
|
if (!this.repeatOn)
|
||||||
|
{
|
||||||
|
if (this.lastKey) this.repeatOn = true;
|
||||||
|
return false; // ignore first keypress after keydown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (e.type == "keyup")
|
||||||
|
{
|
||||||
|
this.lastKey = 0;
|
||||||
|
this.repeatOn = false;
|
||||||
|
}
|
||||||
|
return this.lastKey!=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Nav = function(evt,itemIndex)
|
||||||
|
{
|
||||||
|
var e = (evt) ? evt : window.event; // for IE
|
||||||
|
if (e.keyCode==13) return true;
|
||||||
|
if (!this.ProcessKeys(e)) return false;
|
||||||
|
|
||||||
|
if (this.lastKey==38) // Up
|
||||||
|
{
|
||||||
|
var newIndex = itemIndex-1;
|
||||||
|
var focusItem = this.NavPrev(newIndex);
|
||||||
|
if (focusItem)
|
||||||
|
{
|
||||||
|
var child = this.FindChildElement(focusItem.parentNode.parentNode.id);
|
||||||
|
if (child && child.style.display == 'block') // children visible
|
||||||
|
{
|
||||||
|
var n=0;
|
||||||
|
var tmpElem;
|
||||||
|
while (1) // search for last child
|
||||||
|
{
|
||||||
|
tmpElem = document.getElementById('Item'+newIndex+'_c'+n);
|
||||||
|
if (tmpElem)
|
||||||
|
{
|
||||||
|
focusItem = tmpElem;
|
||||||
|
}
|
||||||
|
else // found it!
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (focusItem)
|
||||||
|
{
|
||||||
|
focusItem.focus();
|
||||||
|
}
|
||||||
|
else // return focus to search field
|
||||||
|
{
|
||||||
|
parent.document.getElementById("MSearchField").focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (this.lastKey==40) // Down
|
||||||
|
{
|
||||||
|
var newIndex = itemIndex+1;
|
||||||
|
var focusItem;
|
||||||
|
var item = document.getElementById('Item'+itemIndex);
|
||||||
|
var elem = this.FindChildElement(item.parentNode.parentNode.id);
|
||||||
|
if (elem && elem.style.display == 'block') // children visible
|
||||||
|
{
|
||||||
|
focusItem = document.getElementById('Item'+itemIndex+'_c0');
|
||||||
|
}
|
||||||
|
if (!focusItem) focusItem = this.NavNext(newIndex);
|
||||||
|
if (focusItem) focusItem.focus();
|
||||||
|
}
|
||||||
|
else if (this.lastKey==39) // Right
|
||||||
|
{
|
||||||
|
var item = document.getElementById('Item'+itemIndex);
|
||||||
|
var elem = this.FindChildElement(item.parentNode.parentNode.id);
|
||||||
|
if (elem) elem.style.display = 'block';
|
||||||
|
}
|
||||||
|
else if (this.lastKey==37) // Left
|
||||||
|
{
|
||||||
|
var item = document.getElementById('Item'+itemIndex);
|
||||||
|
var elem = this.FindChildElement(item.parentNode.parentNode.id);
|
||||||
|
if (elem) elem.style.display = 'none';
|
||||||
|
}
|
||||||
|
else if (this.lastKey==27) // Escape
|
||||||
|
{
|
||||||
|
parent.searchBox.CloseResultsWindow();
|
||||||
|
parent.document.getElementById("MSearchField").focus();
|
||||||
|
}
|
||||||
|
else if (this.lastKey==13) // Enter
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.NavChild = function(evt,itemIndex,childIndex)
|
||||||
|
{
|
||||||
|
var e = (evt) ? evt : window.event; // for IE
|
||||||
|
if (e.keyCode==13) return true;
|
||||||
|
if (!this.ProcessKeys(e)) return false;
|
||||||
|
|
||||||
|
if (this.lastKey==38) // Up
|
||||||
|
{
|
||||||
|
if (childIndex>0)
|
||||||
|
{
|
||||||
|
var newIndex = childIndex-1;
|
||||||
|
document.getElementById('Item'+itemIndex+'_c'+newIndex).focus();
|
||||||
|
}
|
||||||
|
else // already at first child, jump to parent
|
||||||
|
{
|
||||||
|
document.getElementById('Item'+itemIndex).focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (this.lastKey==40) // Down
|
||||||
|
{
|
||||||
|
var newIndex = childIndex+1;
|
||||||
|
var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex);
|
||||||
|
if (!elem) // last child, jump to parent next parent
|
||||||
|
{
|
||||||
|
elem = this.NavNext(itemIndex+1);
|
||||||
|
}
|
||||||
|
if (elem)
|
||||||
|
{
|
||||||
|
elem.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (this.lastKey==27) // Escape
|
||||||
|
{
|
||||||
|
parent.searchBox.CloseResultsWindow();
|
||||||
|
parent.document.getElementById("MSearchField").focus();
|
||||||
|
}
|
||||||
|
else if (this.lastKey==13) // Enter
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setKeyActions(elem,action)
|
||||||
|
{
|
||||||
|
elem.setAttribute('onkeydown',action);
|
||||||
|
elem.setAttribute('onkeypress',action);
|
||||||
|
elem.setAttribute('onkeyup',action);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setClassAttr(elem,attr)
|
||||||
|
{
|
||||||
|
elem.setAttribute('class',attr);
|
||||||
|
elem.setAttribute('className',attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createResults()
|
||||||
|
{
|
||||||
|
var results = document.getElementById("SRResults");
|
||||||
|
for (var e=0; e<searchData.length; e++)
|
||||||
|
{
|
||||||
|
var id = searchData[e][0];
|
||||||
|
var srResult = document.createElement('div');
|
||||||
|
srResult.setAttribute('id','SR_'+id);
|
||||||
|
setClassAttr(srResult,'SRResult');
|
||||||
|
var srEntry = document.createElement('div');
|
||||||
|
setClassAttr(srEntry,'SREntry');
|
||||||
|
var srLink = document.createElement('a');
|
||||||
|
srLink.setAttribute('id','Item'+e);
|
||||||
|
setKeyActions(srLink,'return searchResults.Nav(event,'+e+')');
|
||||||
|
setClassAttr(srLink,'SRSymbol');
|
||||||
|
srLink.innerHTML = searchData[e][1][0];
|
||||||
|
srEntry.appendChild(srLink);
|
||||||
|
if (searchData[e][1].length==2) // single result
|
||||||
|
{
|
||||||
|
srLink.setAttribute('href',searchData[e][1][1][0]);
|
||||||
|
if (searchData[e][1][1][1])
|
||||||
|
{
|
||||||
|
srLink.setAttribute('target','_parent');
|
||||||
|
}
|
||||||
|
var srScope = document.createElement('span');
|
||||||
|
setClassAttr(srScope,'SRScope');
|
||||||
|
srScope.innerHTML = searchData[e][1][1][2];
|
||||||
|
srEntry.appendChild(srScope);
|
||||||
|
}
|
||||||
|
else // multiple results
|
||||||
|
{
|
||||||
|
srLink.setAttribute('href','javascript:searchResults.Toggle("SR_'+id+'")');
|
||||||
|
var srChildren = document.createElement('div');
|
||||||
|
setClassAttr(srChildren,'SRChildren');
|
||||||
|
for (var c=0; c<searchData[e][1].length-1; c++)
|
||||||
|
{
|
||||||
|
var srChild = document.createElement('a');
|
||||||
|
srChild.setAttribute('id','Item'+e+'_c'+c);
|
||||||
|
setKeyActions(srChild,'return searchResults.NavChild(event,'+e+','+c+')');
|
||||||
|
setClassAttr(srChild,'SRScope');
|
||||||
|
srChild.setAttribute('href',searchData[e][1][c+1][0]);
|
||||||
|
if (searchData[e][1][c+1][1])
|
||||||
|
{
|
||||||
|
srChild.setAttribute('target','_parent');
|
||||||
|
}
|
||||||
|
srChild.innerHTML = searchData[e][1][c+1][2];
|
||||||
|
srChildren.appendChild(srChild);
|
||||||
|
}
|
||||||
|
srEntry.appendChild(srChildren);
|
||||||
|
}
|
||||||
|
srResult.appendChild(srEntry);
|
||||||
|
results.appendChild(srResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function init_search()
|
||||||
|
{
|
||||||
|
var results = document.getElementById("MSearchSelectWindow");
|
||||||
|
for (var key in indexSectionLabels)
|
||||||
|
{
|
||||||
|
var link = document.createElement('a');
|
||||||
|
link.setAttribute('class','SelectItem');
|
||||||
|
link.setAttribute('onclick','searchBox.OnSelectItem('+key+')');
|
||||||
|
link.href='javascript:void(0)';
|
||||||
|
link.innerHTML='<span class="SelectionMark"> </span>'+indexSectionLabels[key];
|
||||||
|
results.appendChild(link);
|
||||||
|
}
|
||||||
|
searchBox.OnSelectItem(0);
|
||||||
|
}
|
||||||
|
|
||||||
BIN
html/search/search_l.png
Normal file
|
After Width: | Height: | Size: 604 B |
BIN
html/search/search_m.png
Normal file
|
After Width: | Height: | Size: 158 B |
BIN
html/search/search_r.png
Normal file
|
After Width: | Height: | Size: 612 B |
12
html/search/searchdata.js
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
var indexSectionsWithContent =
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
var indexSectionNames =
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
var indexSectionLabels =
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
BIN
html/splitbar.png
Normal file
|
After Width: | Height: | Size: 314 B |
BIN
html/sync_off.png
Normal file
|
After Width: | Height: | Size: 853 B |
BIN
html/sync_on.png
Normal file
|
After Width: | Height: | Size: 845 B |
BIN
html/tab_a.png
Normal file
|
After Width: | Height: | Size: 142 B |
BIN
html/tab_b.png
Normal file
|
After Width: | Height: | Size: 169 B |
BIN
html/tab_h.png
Normal file
|
After Width: | Height: | Size: 177 B |
BIN
html/tab_s.png
Normal file
|
After Width: | Height: | Size: 184 B |
1
html/tabs.css
Normal file
11
index.html
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="en-US">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="refresh" content="1;url=html/index.html">
|
||||||
|
<title>Page Redirection</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
If you are not redirected automatically, follow the <a href="html/index.html">link to the documentation</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
23
keywords.txt
|
|
@ -1,23 +0,0 @@
|
||||||
#######################################
|
|
||||||
# Syntax Coloring Map for CAN library
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
#######################################
|
|
||||||
# Datatypes (KEYWORD1)
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
|
|
||||||
#######################################
|
|
||||||
# Methods and Functions (KEYWORD2)
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
|
|
||||||
#######################################
|
|
||||||
# Structures (KEYWORD3)
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
|
|
||||||
######################################
|
|
||||||
# Constants (LITERAL1)
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
name=Adafruit CAN
|
|
||||||
version=0.2.0
|
|
||||||
author=Adafruit
|
|
||||||
maintainer=Adafruit <info@adafruit.com>
|
|
||||||
sentence=Arduino library for native CAN.
|
|
||||||
paragraph=Arduino library for native CAN.
|
|
||||||
category=Sensors
|
|
||||||
url=https://github.com/adafruit/Adafruit_CAN
|
|
||||||
architectures=samd
|
|
||||||
|
|
@ -1,216 +0,0 @@
|
||||||
// Copyright (c) Sandeep Mistry. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
#include "CANController.h"
|
|
||||||
|
|
||||||
CANControllerClass::CANControllerClass() :
|
|
||||||
_onReceive(NULL),
|
|
||||||
|
|
||||||
_packetBegun(false),
|
|
||||||
_txId(-1),
|
|
||||||
_txExtended(-1),
|
|
||||||
_txRtr(false),
|
|
||||||
_txDlc(0),
|
|
||||||
_txLength(0),
|
|
||||||
|
|
||||||
_rxId(-1),
|
|
||||||
_rxExtended(false),
|
|
||||||
_rxRtr(false),
|
|
||||||
_rxDlc(0),
|
|
||||||
_rxLength(0),
|
|
||||||
_rxIndex(0)
|
|
||||||
{
|
|
||||||
// overide Stream timeout value
|
|
||||||
setTimeout(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
CANControllerClass::~CANControllerClass()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANControllerClass::begin(long /*baudRate*/)
|
|
||||||
{
|
|
||||||
_packetBegun = false;
|
|
||||||
_txId = -1;
|
|
||||||
_txRtr =false;
|
|
||||||
_txDlc = 0;
|
|
||||||
_txLength = 0;
|
|
||||||
|
|
||||||
_rxId = -1;
|
|
||||||
_rxRtr = false;
|
|
||||||
_rxDlc = 0;
|
|
||||||
_rxLength = 0;
|
|
||||||
_rxIndex = 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CANControllerClass::end()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANControllerClass::beginPacket(int id, int dlc, bool rtr)
|
|
||||||
{
|
|
||||||
if (id < 0 || id > 0x7FF) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dlc > 8) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_packetBegun = true;
|
|
||||||
_txId = id;
|
|
||||||
_txExtended = false;
|
|
||||||
_txRtr = rtr;
|
|
||||||
_txDlc = dlc;
|
|
||||||
_txLength = 0;
|
|
||||||
|
|
||||||
memset(_txData, 0x00, sizeof(_txData));
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANControllerClass::beginExtendedPacket(long id, int dlc, bool rtr)
|
|
||||||
{
|
|
||||||
if (id < 0 || id > 0x1FFFFFFF) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dlc > 8) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_packetBegun = true;
|
|
||||||
_txId = id;
|
|
||||||
_txExtended = true;
|
|
||||||
_txRtr = rtr;
|
|
||||||
_txDlc = dlc;
|
|
||||||
_txLength = 0;
|
|
||||||
|
|
||||||
memset(_txData, 0x00, sizeof(_txData));
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANControllerClass::endPacket()
|
|
||||||
{
|
|
||||||
if (!_packetBegun) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
_packetBegun = false;
|
|
||||||
|
|
||||||
if (_txDlc >= 0) {
|
|
||||||
_txLength = _txDlc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANControllerClass::parsePacket()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
long CANControllerClass::packetId()
|
|
||||||
{
|
|
||||||
return _rxId;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CANControllerClass::packetExtended()
|
|
||||||
{
|
|
||||||
return _rxExtended;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CANControllerClass::packetRtr()
|
|
||||||
{
|
|
||||||
return _rxRtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANControllerClass::packetDlc()
|
|
||||||
{
|
|
||||||
return _rxDlc;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t CANControllerClass::write(uint8_t byte)
|
|
||||||
{
|
|
||||||
return write(&byte, sizeof(byte));
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t CANControllerClass::write(const uint8_t *buffer, size_t size)
|
|
||||||
{
|
|
||||||
if (!_packetBegun) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size > (sizeof(_txData) - _txLength)) {
|
|
||||||
size = sizeof(_txData) - _txLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&_txData[_txLength], buffer, size);
|
|
||||||
_txLength += size;
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANControllerClass::available()
|
|
||||||
{
|
|
||||||
return (_rxLength - _rxIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANControllerClass::read()
|
|
||||||
{
|
|
||||||
if (!available()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _rxData[_rxIndex++];
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANControllerClass::peek()
|
|
||||||
{
|
|
||||||
if (!available()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _rxData[_rxIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
void CANControllerClass::flush()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void CANControllerClass::onReceive(void(*callback)(int))
|
|
||||||
{
|
|
||||||
_onReceive = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANControllerClass::filter(int /*id*/, int /*mask*/)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANControllerClass::filterExtended(long /*id*/, long /*mask*/)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANControllerClass::observe()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANControllerClass::loopback()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANControllerClass::sleep()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANControllerClass::wakeup()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
// Copyright (c) Sandeep Mistry. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
#ifndef CAN_CONTROLLER_H
|
|
||||||
#define CAN_CONTROLLER_H
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
class CANControllerClass : public Stream {
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual int begin(long baudRate);
|
|
||||||
virtual void end();
|
|
||||||
|
|
||||||
int beginPacket(int id, int dlc = -1, bool rtr = false);
|
|
||||||
int beginExtendedPacket(long id, int dlc = -1, bool rtr = false);
|
|
||||||
virtual int endPacket();
|
|
||||||
|
|
||||||
virtual int parsePacket();
|
|
||||||
long packetId();
|
|
||||||
bool packetExtended();
|
|
||||||
bool packetRtr();
|
|
||||||
int packetDlc();
|
|
||||||
|
|
||||||
// from Print
|
|
||||||
virtual size_t write(uint8_t byte);
|
|
||||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
|
||||||
|
|
||||||
// from Stream
|
|
||||||
virtual int available();
|
|
||||||
virtual int read();
|
|
||||||
virtual int peek();
|
|
||||||
virtual void flush();
|
|
||||||
|
|
||||||
virtual void onReceive(void(*callback)(int));
|
|
||||||
|
|
||||||
virtual int filter(int id) { return filter(id, 0x7ff); }
|
|
||||||
virtual int filter(int id, int mask);
|
|
||||||
virtual int filterExtended(long id) { return filterExtended(id, 0x1fffffff); }
|
|
||||||
virtual int filterExtended(long id, long mask);
|
|
||||||
|
|
||||||
virtual int observe();
|
|
||||||
virtual int loopback();
|
|
||||||
virtual int sleep();
|
|
||||||
virtual int wakeup();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
CANControllerClass();
|
|
||||||
virtual ~CANControllerClass();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void (*_onReceive)(int);
|
|
||||||
|
|
||||||
bool _packetBegun;
|
|
||||||
long _txId;
|
|
||||||
bool _txExtended;
|
|
||||||
bool _txRtr;
|
|
||||||
int _txDlc;
|
|
||||||
int _txLength;
|
|
||||||
uint8_t _txData[8];
|
|
||||||
|
|
||||||
long _rxId;
|
|
||||||
bool _rxExtended;
|
|
||||||
bool _rxRtr;
|
|
||||||
int _rxDlc;
|
|
||||||
int _rxLength;
|
|
||||||
int _rxIndex;
|
|
||||||
uint8_t _rxData[8];
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,567 +0,0 @@
|
||||||
// Copyright 2020 © Jeff Epler for Adafruit Industries. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full
|
|
||||||
// license information.
|
|
||||||
|
|
||||||
#if defined(ADAFRUIT_FEATHER_M4_CAN)
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "CANSAME5x.h"
|
|
||||||
#include "wiring_private.h"
|
|
||||||
|
|
||||||
#define DEBUG_CAN (0)
|
|
||||||
#if DEBUG_CAN
|
|
||||||
#define DEBUG_PRINT(...) (Serial.print(__VA_ARGS__), ((void)0))
|
|
||||||
#define DEBUG_PRINTLN(...) (Serial.println(__VA_ARGS__), ((void)0))
|
|
||||||
#else
|
|
||||||
#define DEBUG_PRINT(...) ((void)0)
|
|
||||||
#define DEBUG_PRINTLN(...) ((void)0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
#include "CANSAME5x_port.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
#define hw (reinterpret_cast<Can *>(this->_hw))
|
|
||||||
#define state (reinterpret_cast<_canSAME5x_state *>(this->_state))
|
|
||||||
|
|
||||||
#define DIV_ROUND(a, b) (((a) + (b) / 2) / (b))
|
|
||||||
#define DIV_ROUND_UP(a, b) (((a) + (b)-1) / (b))
|
|
||||||
|
|
||||||
#define GCLK_CAN1 GCLK_PCHCTRL_GEN_GCLK1_Val
|
|
||||||
#define GCLK_CAN0 GCLK_PCHCTRL_GEN_GCLK1_Val
|
|
||||||
#define ADAFRUIT_ZEROCAN_TX_BUFFER_SIZE (1)
|
|
||||||
#define ADAFRUIT_ZEROCAN_RX_FILTER_SIZE (1)
|
|
||||||
#define ADAFRUIT_ZEROCAN_RX_FIFO_SIZE (8)
|
|
||||||
#define ADAFRUIT_ZEROCAN_MAX_MESSAGE_LENGTH (8)
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
template <class T, std::size_t N>
|
|
||||||
constexpr size_t size(const T (&array)[N]) noexcept {
|
|
||||||
return N;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adapted from ASF3 interrupt_sam_nvic.c:
|
|
||||||
|
|
||||||
volatile unsigned long cpu_irq_critical_section_counter = 0;
|
|
||||||
volatile unsigned char cpu_irq_prev_interrupt_state = 0;
|
|
||||||
|
|
||||||
void cpu_irq_enter_critical(void) {
|
|
||||||
if (!cpu_irq_critical_section_counter) {
|
|
||||||
if (__get_PRIMASK() == 0) { // IRQ enabled?
|
|
||||||
__disable_irq(); // Disable it
|
|
||||||
__DMB();
|
|
||||||
cpu_irq_prev_interrupt_state = 1;
|
|
||||||
} else {
|
|
||||||
// Make sure the to save the prev state as false
|
|
||||||
cpu_irq_prev_interrupt_state = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cpu_irq_critical_section_counter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_irq_leave_critical(void) {
|
|
||||||
// Check if the user is trying to leave a critical section
|
|
||||||
// when not in a critical section
|
|
||||||
if (cpu_irq_critical_section_counter > 0) {
|
|
||||||
cpu_irq_critical_section_counter--;
|
|
||||||
|
|
||||||
// Only enable global interrupts when the counter
|
|
||||||
// reaches 0 and the state of the global interrupt flag
|
|
||||||
// was enabled when entering critical state */
|
|
||||||
if ((!cpu_irq_critical_section_counter) && cpu_irq_prev_interrupt_state) {
|
|
||||||
__DMB();
|
|
||||||
__enable_irq();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This appears to be a typo (transposition error) in the ASF4 headers
|
|
||||||
// It's called the "Extended ID Filter Entry"
|
|
||||||
typedef CanMramXifde CanMramXidfe;
|
|
||||||
|
|
||||||
typedef uint32_t can_filter_t;
|
|
||||||
|
|
||||||
struct _canSAME5x_tx_buf {
|
|
||||||
CAN_TXBE_0_Type txb0;
|
|
||||||
CAN_TXBE_1_Type txb1;
|
|
||||||
__attribute__((aligned(4))) uint8_t data[8];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _canSAME5x_rx_fifo {
|
|
||||||
CAN_RXF0E_0_Type rxf0;
|
|
||||||
CAN_RXF0E_1_Type rxf1;
|
|
||||||
__attribute((aligned(4))) uint8_t data[ADAFRUIT_ZEROCAN_MAX_MESSAGE_LENGTH];
|
|
||||||
} can_rx_fifo_t;
|
|
||||||
|
|
||||||
struct _canSAME5x_state {
|
|
||||||
_canSAME5x_tx_buf tx_buffer[ADAFRUIT_ZEROCAN_TX_BUFFER_SIZE];
|
|
||||||
_canSAME5x_rx_fifo rx_fifo[ADAFRUIT_ZEROCAN_RX_FIFO_SIZE];
|
|
||||||
CanMramSidfe standard_rx_filter[ADAFRUIT_ZEROCAN_RX_FILTER_SIZE];
|
|
||||||
CanMramXifde extended_rx_filter[ADAFRUIT_ZEROCAN_RX_FILTER_SIZE];
|
|
||||||
};
|
|
||||||
|
|
||||||
// This data must be in the first 64kB of RAM. The "canram" section
|
|
||||||
// receives special support from the linker file in the Feather M4 CAN's
|
|
||||||
// board support package.
|
|
||||||
__attribute__((section(".canram"))) _canSAME5x_state can_state[2];
|
|
||||||
|
|
||||||
constexpr uint32_t can_frequency = VARIANT_GCLK1_FREQ;
|
|
||||||
bool compute_nbtp(uint32_t baudrate, CAN_NBTP_Type &result) {
|
|
||||||
uint32_t clocks_per_bit = DIV_ROUND(can_frequency, baudrate);
|
|
||||||
uint32_t clocks_to_sample = DIV_ROUND(clocks_per_bit * 7, 8);
|
|
||||||
uint32_t clocks_after_sample = clocks_per_bit - clocks_to_sample;
|
|
||||||
uint32_t divisor = max(DIV_ROUND_UP(clocks_to_sample, 256),
|
|
||||||
DIV_ROUND_UP(clocks_after_sample, 128));
|
|
||||||
if (divisor > 32) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
result.bit.NTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 2;
|
|
||||||
result.bit.NTSEG2 = DIV_ROUND(clocks_after_sample, divisor) - 1;
|
|
||||||
result.bit.NBRP = divisor - 1;
|
|
||||||
result.bit.NSJW = DIV_ROUND(clocks_after_sample, divisor * 4);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
EPioType find_pin(const can_function *table, size_t n, int arduino_pin,
|
|
||||||
int &instance) {
|
|
||||||
if (arduino_pin < 0 || arduino_pin > PINS_COUNT) {
|
|
||||||
return (EPioType)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned port = g_APinDescription[arduino_pin].ulPort;
|
|
||||||
unsigned pin = g_APinDescription[arduino_pin].ulPin;
|
|
||||||
for (size_t i = 0; i < n; i++) {
|
|
||||||
if (table[i].port == port && table[i].pin == pin) {
|
|
||||||
if (instance == -1 || table[i].instance == instance) {
|
|
||||||
DEBUG_PRINT("found #");
|
|
||||||
DEBUG_PRINTLN(i);
|
|
||||||
instance = table[i].instance;
|
|
||||||
return EPioType(table[i].mux);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (EPioType)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
CANSAME5x::CANSAME5x(uint8_t TX_PIN, uint8_t RX_PIN)
|
|
||||||
: _tx(TX_PIN), _rx(RX_PIN) {}
|
|
||||||
#ifdef PIN_CAN_TX
|
|
||||||
CANSAME5x::CANSAME5x() : _tx(PIN_CAN_TX), _rx(PIN_CAN_RX) {}
|
|
||||||
#else
|
|
||||||
CANSAME5x::CANSAME5x() : _tx(-1) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
CANSAME5x::~CANSAME5x() {}
|
|
||||||
|
|
||||||
int CANSAME5x::begin(long baudrate) {
|
|
||||||
if (_tx == -1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_PRINT("_rx ");
|
|
||||||
DEBUG_PRINT(_rx);
|
|
||||||
DEBUG_PRINT(" ulPort=");
|
|
||||||
DEBUG_PRINT(g_APinDescription[_rx].ulPort);
|
|
||||||
DEBUG_PRINT(" ulPin=");
|
|
||||||
DEBUG_PRINTLN(g_APinDescription[_rx].ulPin);
|
|
||||||
|
|
||||||
DEBUG_PRINTLN("rx pin table");
|
|
||||||
for (size_t i = 0; i < size(can_rx); i++) {
|
|
||||||
DEBUG_PRINT(i);
|
|
||||||
DEBUG_PRINT(" port=");
|
|
||||||
DEBUG_PRINT(can_rx[i].port);
|
|
||||||
DEBUG_PRINT(" pin=");
|
|
||||||
DEBUG_PRINT(can_rx[i].pin);
|
|
||||||
DEBUG_PRINT(" instance=");
|
|
||||||
DEBUG_PRINTLN(can_rx[i].instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_PRINT("_tx ");
|
|
||||||
DEBUG_PRINT(_tx);
|
|
||||||
DEBUG_PRINT(" ulPort=");
|
|
||||||
DEBUG_PRINT(g_APinDescription[_tx].ulPort);
|
|
||||||
DEBUG_PRINT(" ulPin=");
|
|
||||||
DEBUG_PRINTLN(g_APinDescription[_tx].ulPin);
|
|
||||||
|
|
||||||
DEBUG_PRINTLN("tx pin table");
|
|
||||||
for (size_t i = 0; i < size(can_tx); i++) {
|
|
||||||
DEBUG_PRINT(i);
|
|
||||||
DEBUG_PRINT(" port=");
|
|
||||||
DEBUG_PRINT(can_tx[i].port);
|
|
||||||
DEBUG_PRINT(" pin=");
|
|
||||||
DEBUG_PRINT(can_tx[i].pin);
|
|
||||||
DEBUG_PRINT(" instance=");
|
|
||||||
DEBUG_PRINTLN(can_tx[i].instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
int instance = -1;
|
|
||||||
EPioType tx_function = find_pin(can_tx, size(can_tx), _tx, instance);
|
|
||||||
EPioType rx_function = find_pin(can_rx, size(can_rx), _rx, instance);
|
|
||||||
|
|
||||||
if (tx_function == EPioType(-1) || rx_function == EPioType(-1) ||
|
|
||||||
instance == -1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CAN_NBTP_Type nbtp;
|
|
||||||
if (!compute_nbtp(baudrate, nbtp)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_idx = instance;
|
|
||||||
_hw = reinterpret_cast<void *>(_idx == 0 ? CAN0 : CAN1);
|
|
||||||
_state = reinterpret_cast<void *>(&can_state[_idx]);
|
|
||||||
|
|
||||||
memset(state, 0, sizeof(*state));
|
|
||||||
|
|
||||||
pinPeripheral(_tx, tx_function);
|
|
||||||
pinPeripheral(_rx, rx_function);
|
|
||||||
|
|
||||||
if (_idx == 0) {
|
|
||||||
GCLK->PCHCTRL[CAN0_GCLK_ID].reg = GCLK_CAN0 | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
|
||||||
} else {
|
|
||||||
GCLK->PCHCTRL[CAN1_GCLK_ID].reg = GCLK_CAN1 | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
|
||||||
}
|
|
||||||
// reset and allow configuration change
|
|
||||||
hw->CCCR.bit.INIT = 1;
|
|
||||||
while (!hw->CCCR.bit.INIT) {
|
|
||||||
}
|
|
||||||
hw->CCCR.bit.CCE = 1;
|
|
||||||
|
|
||||||
// All TX data has an 8 byte payload (max)
|
|
||||||
{
|
|
||||||
CAN_TXESC_Type esc = {};
|
|
||||||
esc.bit.TBDS = CAN_TXESC_TBDS_DATA8_Val;
|
|
||||||
hw->TXESC.reg = esc.reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up TX buffer
|
|
||||||
{
|
|
||||||
CAN_TXBC_Type bc = {};
|
|
||||||
bc.bit.TBSA = (uint32_t)state->tx_buffer;
|
|
||||||
bc.bit.NDTB = ADAFRUIT_ZEROCAN_TX_BUFFER_SIZE;
|
|
||||||
bc.bit.TFQM = 0; // Messages are transmitted in the order submitted
|
|
||||||
hw->TXBC.reg = bc.reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All RX data has an 8 byte payload (max)
|
|
||||||
{
|
|
||||||
CAN_RXESC_Type esc = {};
|
|
||||||
esc.bit.F0DS = CAN_RXESC_F0DS_DATA8_Val;
|
|
||||||
esc.bit.F1DS = CAN_RXESC_F1DS_DATA8_Val;
|
|
||||||
esc.bit.RBDS = CAN_RXESC_RBDS_DATA8_Val;
|
|
||||||
hw->RXESC.reg = esc.reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up RX fifo 0
|
|
||||||
{
|
|
||||||
CAN_RXF0C_Type rxf = {};
|
|
||||||
rxf.bit.F0SA = (uint32_t)state->rx_fifo;
|
|
||||||
rxf.bit.F0S = ADAFRUIT_ZEROCAN_RX_FIFO_SIZE;
|
|
||||||
hw->RXF0C.reg = rxf.reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reject all packets not explicitly requested
|
|
||||||
{
|
|
||||||
CAN_GFC_Type gfc = {};
|
|
||||||
gfc.bit.RRFE = 0;
|
|
||||||
gfc.bit.ANFS = CAN_GFC_ANFS_REJECT_Val;
|
|
||||||
gfc.bit.ANFE = CAN_GFC_ANFE_REJECT_Val;
|
|
||||||
hw->GFC.reg = gfc.reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initially, receive all standard and extended packets to FIFO 0
|
|
||||||
state->standard_rx_filter[0].SIDFE_0.bit.SFID1 = 0; // ID
|
|
||||||
state->standard_rx_filter[0].SIDFE_0.bit.SFID2 = 0; // mask
|
|
||||||
state->standard_rx_filter[0].SIDFE_0.bit.SFEC = CAN_SIDFE_0_SFEC_STF0M_Val;
|
|
||||||
state->standard_rx_filter[0].SIDFE_0.bit.SFT = CAN_SIDFE_0_SFT_CLASSIC_Val;
|
|
||||||
|
|
||||||
state->extended_rx_filter[0].XIDFE_0.bit.EFID1 = 0; // ID
|
|
||||||
state->extended_rx_filter[0].XIDFE_0.bit.EFEC = CAN_XIDFE_0_EFEC_STF0M_Val;
|
|
||||||
state->extended_rx_filter[0].XIDFE_1.bit.EFID2 = 0; // mask
|
|
||||||
state->extended_rx_filter[0].XIDFE_1.bit.EFT = CAN_XIDFE_1_EFT_CLASSIC_Val;
|
|
||||||
|
|
||||||
// Set up standard RX filters
|
|
||||||
{
|
|
||||||
CAN_SIDFC_Type dfc = {};
|
|
||||||
dfc.bit.LSS = ADAFRUIT_ZEROCAN_RX_FILTER_SIZE;
|
|
||||||
dfc.bit.FLSSA = (uint32_t)state->standard_rx_filter;
|
|
||||||
hw->SIDFC.reg = dfc.reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up extended RX filters
|
|
||||||
{
|
|
||||||
CAN_XIDFC_Type dfc = {};
|
|
||||||
dfc.bit.LSE = ADAFRUIT_ZEROCAN_RX_FILTER_SIZE;
|
|
||||||
dfc.bit.FLESA = (uint32_t)state->extended_rx_filter;
|
|
||||||
hw->XIDFC.reg = dfc.reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable receive IRQ (masked until enabled in NVIC)
|
|
||||||
hw->IE.bit.RF0NE = true;
|
|
||||||
if (_idx == 0) {
|
|
||||||
hw->ILE.bit.EINT0 = true;
|
|
||||||
} else {
|
|
||||||
hw->ILE.bit.EINT1 = true;
|
|
||||||
}
|
|
||||||
hw->ILS.bit.RF0NL = _idx;
|
|
||||||
|
|
||||||
// Set nominal baud rate
|
|
||||||
hw->NBTP.reg = nbtp.reg;
|
|
||||||
|
|
||||||
// hardware is ready for use
|
|
||||||
hw->CCCR.bit.CCE = 0;
|
|
||||||
hw->CCCR.bit.INIT = 0;
|
|
||||||
while (hw->CCCR.bit.INIT) {
|
|
||||||
}
|
|
||||||
|
|
||||||
instances[_idx] = this;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CANSAME5x::end() {
|
|
||||||
instances[_idx] = 0;
|
|
||||||
pinMode(_tx, INPUT);
|
|
||||||
pinMode(_rx, INPUT);
|
|
||||||
// reset and disable clock
|
|
||||||
hw->CCCR.bit.INIT = 1;
|
|
||||||
while (!hw->CCCR.bit.INIT) {
|
|
||||||
}
|
|
||||||
if (_idx == 0) {
|
|
||||||
GCLK->PCHCTRL[CAN0_GCLK_ID].reg = 0;
|
|
||||||
} else {
|
|
||||||
GCLK->PCHCTRL[CAN1_GCLK_ID].reg = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANSAME5x::endPacket() {
|
|
||||||
if (!CANControllerClass::endPacket()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bus_autorecover();
|
|
||||||
|
|
||||||
// TODO wait for TX buffer to free
|
|
||||||
|
|
||||||
_canSAME5x_tx_buf &buf = state->tx_buffer[0];
|
|
||||||
buf.txb0.bit.ESI = false;
|
|
||||||
buf.txb0.bit.XTD = _txExtended;
|
|
||||||
buf.txb0.bit.RTR = _txRtr;
|
|
||||||
if (_txExtended) {
|
|
||||||
buf.txb0.bit.ID = _txId;
|
|
||||||
} else {
|
|
||||||
buf.txb0.bit.ID = _txId << 18;
|
|
||||||
}
|
|
||||||
buf.txb1.bit.MM = 0;
|
|
||||||
buf.txb1.bit.EFC = 0;
|
|
||||||
buf.txb1.bit.FDF = 0;
|
|
||||||
buf.txb1.bit.BRS = 0;
|
|
||||||
buf.txb1.bit.DLC = _txLength;
|
|
||||||
|
|
||||||
if (!_txRtr) {
|
|
||||||
memcpy(buf.data, _txData, _txLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TX buffer add request
|
|
||||||
hw->TXBAR.reg = 1;
|
|
||||||
|
|
||||||
// wait 8ms (hard coded for now) for TX to occur
|
|
||||||
for (int i = 0; i < 8000; i++) {
|
|
||||||
if (hw->TXBTO.reg & 1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
yield();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANSAME5x::_parsePacket() {
|
|
||||||
if (!hw->RXF0S.bit.F0FL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int index = hw->RXF0S.bit.F0GI;
|
|
||||||
auto &hw_message = state->rx_fifo[index];
|
|
||||||
|
|
||||||
_rxExtended = hw_message.rxf0.bit.XTD;
|
|
||||||
_rxRtr = hw_message.rxf0.bit.RTR;
|
|
||||||
_rxDlc = hw_message.rxf1.bit.DLC;
|
|
||||||
|
|
||||||
if (_rxExtended) {
|
|
||||||
_rxId = hw_message.rxf0.bit.ID;
|
|
||||||
} else {
|
|
||||||
_rxId = hw_message.rxf0.bit.ID >> 18;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_rxRtr) {
|
|
||||||
_rxLength = 0;
|
|
||||||
} else {
|
|
||||||
_rxLength = _rxDlc;
|
|
||||||
memcpy(_rxData, hw_message.data, _rxLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
_rxIndex = 0;
|
|
||||||
|
|
||||||
hw->RXF0A.bit.F0AI = index;
|
|
||||||
|
|
||||||
return _rxDlc;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANSAME5x::parsePacket() {
|
|
||||||
cpu_irq_enter_critical();
|
|
||||||
bus_autorecover();
|
|
||||||
int result = _parsePacket();
|
|
||||||
cpu_irq_leave_critical();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CANSAME5x::onReceive(void (*callback)(int)) {
|
|
||||||
CANControllerClass::onReceive(callback);
|
|
||||||
|
|
||||||
auto irq = _idx == 0 ? CAN0_IRQn : CAN1_IRQn;
|
|
||||||
if (callback) {
|
|
||||||
NVIC_EnableIRQ(irq);
|
|
||||||
} else {
|
|
||||||
NVIC_DisableIRQ(irq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CANSAME5x::handleInterrupt() {
|
|
||||||
uint32_t ir = hw->IR.reg;
|
|
||||||
|
|
||||||
if (ir & CAN_IR_RF0N) {
|
|
||||||
while (int i = parsePacket())
|
|
||||||
_onReceive(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
hw->IR.reg = ir;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANSAME5x::filter(int id, int mask) {
|
|
||||||
// accept matching standard messages
|
|
||||||
state->standard_rx_filter[0].SIDFE_0.bit.SFID1 = id;
|
|
||||||
state->standard_rx_filter[0].SIDFE_0.bit.SFID2 = mask;
|
|
||||||
state->standard_rx_filter[0].SIDFE_0.bit.SFEC = CAN_SIDFE_0_SFEC_STF0M_Val;
|
|
||||||
state->standard_rx_filter[0].SIDFE_0.bit.SFT = CAN_SIDFE_0_SFT_CLASSIC_Val;
|
|
||||||
|
|
||||||
// reject all extended messages
|
|
||||||
state->extended_rx_filter[0].XIDFE_0.bit.EFID1 = 0; // ID
|
|
||||||
state->extended_rx_filter[0].XIDFE_0.bit.EFEC = CAN_XIDFE_0_EFEC_REJECT_Val;
|
|
||||||
state->extended_rx_filter[0].XIDFE_1.bit.EFID2 = 0; // mask
|
|
||||||
state->extended_rx_filter[0].XIDFE_1.bit.EFT = CAN_XIDFE_1_EFT_CLASSIC_Val;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANSAME5x::filterExtended(long id, long mask) {
|
|
||||||
// reject all standard messages
|
|
||||||
state->standard_rx_filter[0].SIDFE_0.bit.SFID1 = 0;
|
|
||||||
state->standard_rx_filter[0].SIDFE_0.bit.SFID2 = 0;
|
|
||||||
state->standard_rx_filter[0].SIDFE_0.bit.SFEC = CAN_SIDFE_0_SFEC_REJECT_Val;
|
|
||||||
state->standard_rx_filter[0].SIDFE_0.bit.SFT = CAN_SIDFE_0_SFT_CLASSIC_Val;
|
|
||||||
|
|
||||||
// accept matching extended messages
|
|
||||||
state->extended_rx_filter[0].XIDFE_0.bit.EFID1 = id;
|
|
||||||
state->extended_rx_filter[0].XIDFE_0.bit.EFEC = CAN_XIDFE_0_EFEC_STF0M_Val;
|
|
||||||
state->extended_rx_filter[0].XIDFE_1.bit.EFID2 = mask;
|
|
||||||
state->extended_rx_filter[0].XIDFE_1.bit.EFT = CAN_XIDFE_1_EFT_CLASSIC_Val;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANSAME5x::observe() {
|
|
||||||
hw->CCCR.bit.INIT = 1;
|
|
||||||
while (!hw->CCCR.bit.INIT) {
|
|
||||||
}
|
|
||||||
hw->CCCR.bit.CCE = 1;
|
|
||||||
|
|
||||||
hw->CCCR.bit.MON = 1;
|
|
||||||
|
|
||||||
hw->CCCR.bit.CCE = 0;
|
|
||||||
hw->CCCR.bit.INIT = 0;
|
|
||||||
while (hw->CCCR.bit.INIT) {
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANSAME5x::loopback() {
|
|
||||||
hw->CCCR.bit.INIT = 1;
|
|
||||||
while (!hw->CCCR.bit.INIT) {
|
|
||||||
}
|
|
||||||
hw->CCCR.bit.CCE = 1;
|
|
||||||
|
|
||||||
hw->CCCR.bit.TEST = 1;
|
|
||||||
hw->TEST.bit.LBCK = 1;
|
|
||||||
|
|
||||||
hw->CCCR.bit.CCE = 0;
|
|
||||||
hw->CCCR.bit.INIT = 0;
|
|
||||||
while (hw->CCCR.bit.INIT) {
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANSAME5x::sleep() {
|
|
||||||
hw->CCCR.bit.CSR = 1;
|
|
||||||
while (!hw->CCCR.bit.CSA) {
|
|
||||||
}
|
|
||||||
if (_idx == 0) {
|
|
||||||
GCLK->PCHCTRL[CAN0_GCLK_ID].reg = 0;
|
|
||||||
} else {
|
|
||||||
GCLK->PCHCTRL[CAN1_GCLK_ID].reg = 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CANSAME5x::wakeup() {
|
|
||||||
if (_idx == 0) {
|
|
||||||
GCLK->PCHCTRL[CAN0_GCLK_ID].reg = GCLK_CAN0 | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
|
||||||
} else {
|
|
||||||
GCLK->PCHCTRL[CAN1_GCLK_ID].reg = GCLK_CAN1 | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
|
||||||
}
|
|
||||||
hw->CCCR.bit.INIT = 0;
|
|
||||||
while (hw->CCCR.bit.INIT) {
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CANSAME5x::bus_autorecover() {
|
|
||||||
if (hw->PSR.bit.BO) {
|
|
||||||
DEBUG_PRINTLN("bus autorecovery activated");
|
|
||||||
hw->CCCR.bit.INIT = 0;
|
|
||||||
while (hw->CCCR.bit.INIT) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CANSAME5x::onInterrupt() {
|
|
||||||
for (int i = 0; i < size(instances); i++) {
|
|
||||||
CANSAME5x *instance = instances[i];
|
|
||||||
if (instance) {
|
|
||||||
instance->handleInterrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" __attribute__((externally_visible)) void CAN0_Handler() {
|
|
||||||
cpu_irq_enter_critical();
|
|
||||||
CANSAME5x::onInterrupt();
|
|
||||||
cpu_irq_leave_critical();
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" __attribute__((externally_visible)) void CAN1_Handler() {
|
|
||||||
cpu_irq_enter_critical();
|
|
||||||
CANSAME5x::onInterrupt();
|
|
||||||
cpu_irq_leave_critical();
|
|
||||||
}
|
|
||||||
|
|
||||||
CANSAME5x *CANSAME5x::instances[2];
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
// Copyright 2020 © Jeff Epler for Adafruit Industries. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full
|
|
||||||
// license information.
|
|
||||||
|
|
||||||
#include "CANController.h"
|
|
||||||
|
|
||||||
class CANSAME5x : public CANControllerClass {
|
|
||||||
public:
|
|
||||||
CANSAME5x();
|
|
||||||
CANSAME5x(uint8_t tx_pin, uint8_t rx_pin);
|
|
||||||
~CANSAME5x() final;
|
|
||||||
|
|
||||||
int begin(long baudRate) final;
|
|
||||||
void end() final;
|
|
||||||
|
|
||||||
int endPacket() final;
|
|
||||||
|
|
||||||
int parsePacket() final;
|
|
||||||
|
|
||||||
void onReceive(void (*callback)(int)) final;
|
|
||||||
|
|
||||||
using CANControllerClass::filter;
|
|
||||||
int filter(int id, int mask) final;
|
|
||||||
using CANControllerClass::filterExtended;
|
|
||||||
int filterExtended(long id, long mask) final;
|
|
||||||
|
|
||||||
int observe() final;
|
|
||||||
int loopback() final;
|
|
||||||
int sleep() final;
|
|
||||||
int wakeup() final;
|
|
||||||
|
|
||||||
// void dumpRegisters(Stream &out);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void bus_autorecover();
|
|
||||||
|
|
||||||
void handleInterrupt();
|
|
||||||
|
|
||||||
int _parsePacket();
|
|
||||||
|
|
||||||
private:
|
|
||||||
int8_t _tx, _rx;
|
|
||||||
int8_t _idx;
|
|
||||||
// intr_handle_t _intrHandle;
|
|
||||||
void *_state;
|
|
||||||
void *_hw;
|
|
||||||
static CANSAME5x *instances[2];
|
|
||||||
|
|
||||||
static void onInterrupt();
|
|
||||||
|
|
||||||
friend void CAN0_Handler(void);
|
|
||||||
friend void CAN1_Handler(void);
|
|
||||||
};
|
|
||||||