
Originally Posted by
jakeselectronics
I dont know any other way :s
The other way is to define solely the structure of the document using HTML, then apply layout using a style sheet.
What follows is an alternative implementation of both the script and document style. You can reuse it on any number of pages. For the script to work, you start an input's name with "bit" (or "b" or "bits"), followed by a list of bit positions to set or clear using the input's value. In the list, use an underscore or a dash to separate positions, where an underscore will skip intervening positions and a dash will include them. For example, "<input name='bit5_7_9-12' value='57'/>" will set bits 5,10,11,12 to 1 and bits 7,9 to 0 (57 == 0b111001). Also, have an input named "display" and call initPICForm(...) on the form with the radio buttons. The script takes care of the rest, including sizing the display field and registering the event listeners. It still needs to be tested on all IE versions.
Note you could easily have PHP (or other server side script) generate the form from a fairly terse description of the bit fields.
HTML Code:
...
<link href="style/PIC.css" rel="stylesheet" type="text/css">
</head>
<body>
...
<form name="PICbits" onsubmit="update(this); return false;">
<ul class="bitfields">
<li>bit 13: <span class="bitName">CP</span>: Flash Program Memory Code Protection bit(2)<ul>
<li><input type="radio" name="bit13" value="1" />1 = Code protection off</li>
<li><input type="radio" name="bit13" value="0" checked/>
0 = 0000h to 0FFFh (<span class="controller">PIC16F648A</span>),
07FFh (<span class="controller">PIC16F628A</span>) or
03FFh (<span class="controller">PIC16F627A</span>) code protected</li>
</ul></li>
<li>bits 12-9: unused</li>
<li>bit 8: <ul>
<li><input type="radio" name="bit8" value="1" checked/>1 = </li>
<li><input type="radio" name="bit8" value="0"/>0 = </li>
</ul></li>
....
<li>bit 4,1,0: <span class="bitName">FOSC2:FOSC0</span>:Oscillator Selection bits(4)<ul>
<li><input type="radio" name="bit0_1_4" value="7"/>111 = </li>
<li><input type="radio" name="bit0_1_4" value="6"/>110 = </li>
<li><input type="radio" name="bit0_1_4" value="5"/>101 = ...</li>
<li><input type="radio" name="bit0_1_4" value="4"/>100 = ...</li>
<li><input type="radio" name="bit0_1_4" value="3"/>011 = ...</li>
<li><input type="radio" name="bit0_1_4" value="2"/>010 = ...</li>
<li><input type="radio" name="bit0_1_4" value="1"/>001 = ...</li>
<li><input type="radio" name="bit0_1_4" value="0"/>000 = ...</li>
</ul></li>
</ul>
<input name="display" readonly size='0' />
</form>
<script src="js/PIC.js"></script>
<script type="text/javascript">
initPICForm(document.forms.PICbits);
</script>
PIC.js:
Code:
function BitVector(n) {
this.length = n || 16;
this.data=0;
}
BitVector.prototype.put = function(i, v) {
this.data = (this.data & ~(1 << i)) | (v << i);
};
BitVector.prototype.putAll = function(pos, val) {
pos = pos.sort();
for (p in pos) {
this.put(pos[p], val & 1);
val >>= 1;
}
};
BitVector.prototype.at = function(i) {
(this.data >> i) & 1;
};
BitVector.prototype.toString_big = function() {
return this.data.toString(2).pad(this.length, '0');
};
BitVector.prototype.toString_little = function() {
return this.toString_big().reverse();
};
BitVector.prototype.toString = BitVector.prototype.toString_little;
String.prototype.pad = function(minWidth, padChar) {
padChar = padChar || ' ';
pad = Math.max(0, minWidth - this.length);
/* quick 'n' dirty padding. Could also define a String.repeat(n) method,
using peasant multiplication */
return (new Array(pad+1)).join(padChar) + this;
};
String.prototype.reverse = function() {
return this.split('').reverse().join('');
};
function initPICForm(form) {
var size=0, indices;
form.bits=new BitVector();
form.bitFields = {};
for (i in form.elements) {
el = form.elements[i];
if (/^b(?:its?)?\d([-_0-9]*\d)?$/.test(el.name)) {
if (!form.bitFields[el.name]) {
indices=form.bitFields[el.name]=bitIndices(el.name);
size = Math.max(size, indices[indices.length-1]);
}
el.indices=form.bitFields[el.name];
if ('radio' == el.type) {
el.onclick = function() {setBits(this);};
}
if (el.checked) {
setBits(el);
}
}
}
++size;
form.bits.length = size;
form.display.size = Math.max(size, form.display.size);
display(form);
}
function bitIndices(name) {
var indices = [],
spec, n,
specs = name.match(/\d+(?:-\d+)?/g);
for (s in specs) {
if (spec = specs[s].match(/(\d+)-(\d+)/)) {
n = parseInt(spec[2]);
for (var m=parseInt(spec[1]); m <= n;++m) {
indices.push(m);
}
} else {
indices.push(specs[s]);
}
}
return indices.sort();
}
function setBits(input) {
input.form.bits.putAll(
input.indices || (input.indices=bitIndices(input.name)),
input.value);
display(input.form);
}
function display(form) {
form.display.value = form.bits.toString();
}
function update(form) {
for (i in form.elements) {
if (form.elements[i].indices) {
form.bits.putAll(form.elements[i].indices, form.elements[i].indices);
}
}
return false;
}
The maximum length of a BitVector (as implemented) is limited to the size of a platform integer (probably 32 bits). As you're probably not dealing with 64 bit microcontrollers, this isn't an issue. If you don't like the implementation of BitVector, you can easily replace it with one based on an Array. As long as you don't change the BitVector API (in particular, BitVector.put, .putAll, .toString and .length), you don't need to change anything else.
You could have a checkbox to easily toggle between bit endianness in the display. You could also change the display from a simple field to a labeled table, rather like the first two rows of the current table.
HTML Code:
<thead>
<tr><th>CP</th><th>-</th><th>CPD</th>...</tr>
</thead>
<tbody>
<tr><td id="b13">0</td><td id="b9-12">00000</td><td id="b8">0</td>...</tr>
</tbody>
</table>
PIC.css:
Code:
ul.bitfields, .bitfields ul {
list-style-type: none;
}
span.controller {
text-decoration: underline;
}
.bitName {
font-weight: bold;
}
// ...