Tuesday, December 30, 2014

Stalling Aircraft

Modern passenger planes cruise at very high altitude and very close to their stall speed, flying on a knife edge, in order to minimize fuel consumption.  The problem is that when a plane encounters turbulent air due to a storm or a side wind, it can stall unexpectedly, while still traveling at high speed.

It appears to me, that in the relentless pursuit of lower drag and lower fuel consumption, the designers have compromised aircraft stability and safety. 

The situation now, that a passenger plane can stall at 30,000 feet and then fall out of the sky, with the total loss of aircraft, crew and passengers, unable to recover despite the best efforts of an experienced flight crew, because the plane was designed to save every last drop of fuel, is inexcusable.

Aircraft designers should always put stability and safety first and should not be driven by marketing only.

Postscript
In October 2018, a brand new Boeing 737 Max crashed in Indonesia with great loss of life, because it had a new anti-stall feature that the pilots were not informed of.  The plane was forced down by the automatic system, due to a faulty AOA sensor and crashed into the sea, while the pilots were fighting the system for control - but the manual trim control wheel required super human strength to turn, as it was made smaller a few years prior in another unintentional bungle.

Maybe airlines should consider buying more conservatively designed Ukrainian and Russian planes, instead of badly engineered American ones.

Postmortemscript
This is not good at all.  Another 737 Max 8 went down in early March 2019, with very serious loss of life.

Of course, Boeing maintains that their planes are perfectly safe, while a writer at Tech Republic called the Max the world's first Self Highjacking Plane - for its propensity to deliberately fly itself into the ground.

Even Prez Trump weighed in that planes should be simpler and easier to fly.  I think plane designers should take note - not only Boeing, everyone.

The result is that Boeing has hundreds of planes, that nobody wants to fly in and every month they add another 42 coming off the production line (From the Douglas Adams Book of Bistro Management), so their employee parking lots are now filling up with the unloved planes and by the end of 2019 they will have to park another 300 new planes somewhere in the desert, while all the employees will have to bicycle to work since there would be nowhere to park their cars.



Airlines have the Max 8s stuffed at out of the way airports all over the world:
https://thepointsguy.com/news/heres-where-airlines-are-storing-the-boeing-737-max/

Boeing may go bankrupt because of the lost sales and law suits.


Herman

Tuesday, December 23, 2014

FreeCAD

I've been playing with FreeCAD for a few hours, since I need to make little Nylon brackets and things at Shapeways.

The program is absolutely amazing for its price - Zero Dollars - which is a nice way to say that there are a few hiccups, but once one knows how to avoid the hiccups, then it works perfectly... :)

Antique Radio Ham Speaker Mic, circa 2015

To aid with error checking of CAD files before uploading them to Shapeways, also install the free Meshlab.  Note that uploading a file to Shapeways takes a while, because they also do a conversion and error check, so be patient.  If you checked it with Meshlab, then it should work.


I made the above widget by drawing four cubes, resizing them and subtracting  three from the other, then subtracting four cylinders for the mounting holes and finally applying fillets to the edges.  That's all there is to it.  Made out of Nylon, it makes a strong base for a little step motor.

In general, I would say that FreeCAD is almost as good as Solidworks.   It is certainly good for hobby use and it may even be good enough in a small business for simple things.

The nice thing about FreeCAD, is that it is cross platform and it works exactly the same way on Windows, Linux and Mac - it even has the same bugs too...

Here are a few pointers on FreeCAD version 0.14:

The smallest features that Shapeways can produce is about 1 mm.  Widgets may also be somewhat uneven and may require sanding/polishing, but the resulting whatchammacallits are generally fine for prototype and hobby use as is.

If you keep the thickness at 1 mm, then the cost is about 50c per 10 square cm for the cheapest Nylon.  This schtuff is very strong and slightly flexible.  If you need it to be stiff - make curved surfaces or add some ribs.

The only CAD export format that I can get to work consistently with Shapeways, is STL, but FreeCAD cannot export to STL.  So, I Select All, then export to WRL, import that file into Meshlab and export it again to STL, then upload that to Shapeways. (Update: The 2018 version of FreeCAD can export to STL binary format.  If you need ASCII, then convert it with Meshlab by unselecting 'Binary' when you save the file to STL)

To save a model in WRL, Click Part Workbench, Edit, Select All, Ctrl-E, then type filename.wrl, SaveThere is more information down below on how to make holy or unholy shapes...

I wanted to make an old fashioned Radio Ham handheld/standing Microphone/Speaker/PTT gadget, that looks like it was stamped out of brass, circa 1920 or so.  Here is the base:




It is also recommended to check the final file with Meshlab before sending it to Shapeways.  If the file is full of holes, or if the Shapeways uploader complains about the file being unusable, change the maximum mesh edge length to something smaller and try again as explained down below.

If you make a drawing using the 3D add/subtract method in the Part Workbench, then the whole hoosammawatzit seems to remain fully constrained all by itself.  This is a wonderful way to make a little wazzisname consisting of rectangular shapes and cylindrical holes very quickly and is the drafting method that I can recommend to occasional users.  Follow this tutorial: http://www.freecadweb.org/wiki/index.php?title=Basic_modeling_tutorial

If you make a watchammacallit using the 2D drawing and extrusion process in the Part Design WorkBench, then you have to keep an eye on the constraints box and ensure that every single line or shape is fully constrained before moving on to the next line or shape.  It is almost impossible to fix missing constraints later, but you may be able to find a loose end by clicking and dragging lines with the mouse - if it moves, then it isn't fully constrained.

The best way to draw a fully constrained line in the Part Design Workbench, is to draw the line close to where you want it to be, but not exactly.  Then click the end point and the point where you want it to be and apply a constraint (a dot 'coincident', or 'fix point to object' or some such), to make the line end point jump to the right spot.  You typically need to apply two to three constraints to get it exactly where it should be.  Watch the Constraints box on the left.

Here is the Speaker front and the tiny little hole at the top is for the Mic (The backside looks similar but without the rose of holes):



So now I can put my $20 of amplifier electronics inside a seemingly century old custom plastic enclosure costing $80 - ouch.  It is not a cheap hobby...

When making plastic/metal nurgles, it is important that you fillet/chamfer the edges.  Stress build up at edges can cause a plastic mcgafter to crack and metal thingammajigs may cut your fingers if you don't.  The fillet tool is a little unreliable, so save oftenDo this step last.

Sometimes (not very often!) FreeCAD exits, or the drawing disappears from view, leaving you rubbing your eyes and reaching for your mug of coffee in frustration.  The only solution is to restart it and get yet more coffee.  It is therefore important to save your work regularly and use an incrementing number for simple version control (filename-1, filename-2), so that you can go back to the last thingammabob that worked.

Manufacturing Issues At Shapeways

I ordered the above parts in black plastic and what I got, was white plastic, painted/dyed black.  That is not the same thing at all.

The problem being that if you have to rework a part then you need to repaint everything, so you can just as well order the parts in white plastic to begin with.

Some features that were supposed to be hollow, turned out solid.  All the carefully designed mountings for potentiometers and the speaker grill, came out solid.

So, be prepared to do some rework with a drill/dremel/rasp to get things into shape.  The white plastic of course melts if you use too much speed, but if you take it slowly, then you can drill holes and cut pieces to shape.

Even with rework, the final result should be much more satisfying than housing a project in a traditional tobacco tin or soap box!

Holy Shapes

I finally figured out how to make holy shapes.  The problem is that Shapeways uses mesh files, which are very simple things.  When you convert a CAD drawing to a mesh, much information is lost.  If the mesh is 'too coarse', then some legitimate holes in your object may get filled in by the automatic hole filling software that Shapeways uses and the object then becomes rather unholy...

The solution is to go to the Mesh Workbench in FreeCAD, select the whole object, then go to Mesh, Convert Object to Mesh and select a maximum mesh edge length of 1.5 to 2 mm, instead of the default 7.8 mm.  Then when you export the file to a mesh (Export as WRL file, then load that into Meshlab and export as STL file) the resulting object should be holy.  If FreeCAD quits unexpectedly, it is because it ran out of RAM while meshing - then you need to get a better computer.

Finishing

I finally got the Speaker Mic together and stuck a pic at the top of this page.  I burned out my Dremel in the process.  I have found that Dremels are really pathetic, having burned out two of them in 5 years working on plastic and balsa wood - need to find something better.

Shapeways offer many different materials apart from cheap 20c per cm3 plastic.  If you need something strong, then you could use steel at $5 per cm3, but reworking a steel part is difficult, while brass and bronze are expensive at $16 per cm3, but they now offer Aluminium at $7 per cm3, which is better.

Note that if your object quoted price turns out to be eye wateringly expensive, then the automatic hole filling software probably made some parts solid that should have been hollow.  In that case, go back and remesh with a smaller side length.

La voila!


Monday, December 22, 2014

Tor Exit Nodes Compromised


https://www.torproject.org/docs/tor-manual.html.en

ExcludeExitNodes node,node,…
A list of identity fingerprints, nicknames, country codes and address patterns of nodes to never use when picking an exit node---that is, a node that delivers traffic for you outside the Tor network. Note that any node listed in ExcludeNodes is automatically considered to be part of this list too. See also the caveats on the "ExitNodes" option below. 

Tor users should note and temporarily avoid the affected mirrors below:

https://globe.thecthulhu.com
https://atlas.thecthulhu.com
https://compass.thecthulhu.com
https://onionoo.thecthulhu.com
http://globe223ezvh6bps.onion
http://atlas777hhh7mcs7.onion
http://compass6vpxj32p3.onion
77.95.229.11
77.95.229.12
77.95.229.14
77.95.229.16
77.95.229.17
77.95.229.18
77.95.229.19
77.95.229.20
77.95.229.21
77.95.229.22
77.95.229.23
77.95.224.187
89.207.128.241
5.104.224.15
128.204.207.215

Saturday, December 20, 2014

Sony

Sony, the company that distributed millions of MS Windows root kits on CD in 2005 https://en.wikipedia.org/wiki/Sony_BMG_copy_protection_rootkit_scandal, has now been hacked through a Windows SMB exploit https://www.us-cert.gov/ncas/alerts/TA14-353A.

I don't have much sympathy with this crowd, since they cost the IT world an enormous amount of money to clean up their root kit mess and blaming their current disaster on North Korea just doesn't fly with me.  I don't see how someone can download terabytes of data over the North Korean antiquated  internet link.
 
Clearly the Sony IT staff and management were stupid in 2005 and they are still
stupid today. They haven't learned anything.

On November 4, 2005. Thomas Hesse, Sony BMG's Global Digital Business President, told reporter Neda Ulaby, "Most people, I think, don't even know what a rootkit is, so why should they care about it?"

Now suddenly, they care deeply...

If I apply Occam's Razor, then one of their clueless IT Administrators likely left SMB ports 135 to 139 open on a router and used WORKGROUP and Admin/admin as user name and password, on one or more old and unpatched Windows 2000 server(s), thus handing a gang of script kiddies access on a silver platter.

We shall see...

Friday, December 19, 2014

SSH Daemon on a Mac

A Mac is a weird thing that doesn't always know whether it wants to be BSD or Linux.

Here is the magical incantation to start a SSH Server:
$ sudo launchctl start /System/Library/LaunchDaemons/ssh.plist

One can then check it with a Telnet client:
$ telnet localhost ssh 
 Trying ::1... 
 Connected to localhost. Escape character is '^]'. 
 SSH-2.0-OpenSSH_6.2 ^] 
 telnet> q 
 Connection closed. 

Now you can use scp and ssh from another machine on the LAN, but one needs to know what the IP address is:
$ ifconfig en0 | grep inet 
inet6 fe80::5626:96ff:fece:371f%en0 prefixlen 64 scopeid 0x4 
inet 192.168.1.5 netmask 0xffffff00 broadcast 192.168.1.255


Run SSHD On A Different Port

If you want to allow internet access to your Mac and don't want to be bothered by script kiddies all the time, then you need to change sshd to a different port. 

The Mac launchctl system seems to ignore the /etc/sshd_conf file.  The only way that I could convince it to run on a different port, was by editing the /etc/services file and then reloading sshd with launchctl.

$ sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist
$ sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist
 

This will automatically change the firewall port also. 


La voila!


Sunday, November 2, 2014

Apple Mac NTFS Read/Write Support

Apple Macs have NTFS support, but for some inexplicable reason, it defaults to read only when you plug a NTFS removable disk in.

There must be a way to change this, but the simple workaround is to mount the annoying thing manually:

First open a terminal and become super user:
$ sudo su
password

Plug the removable disk in, then:
# dmesg

Look to see what device name is used, probably disk2s1.

To ensure that it is free, in case it was 'helpfully' auto mounted already:
# umount /dev/disk2s1

Make a directory as a mount point:
# mkdir mnt

Mount the device read/write:

# mount -t ntfs -o rw,auto,nobrowse /dev/disk2s1 mnt

Now open Finder and copy to/from the new mount point.

When you are done, unmount it with:
# sync
# umount /dev/disk2s1

Hot Mac Problems

Another unrelated issue is with a Mac running very hot due to the mdworker thread.  This stupid thing is the Mac spotlight index utility.  If I want to find something, I use the find utility, I don't need a background process that scans the disk and runs the battery down.

This works for me:
$ sudo su -
password

# ls /Volumes/
Macintosh HD    Preboot


# mdutil -i off "/Volumes/Macintosh HD"

mdutil disabling Spotlight: / -> kMDConfigSearchLevelFSSearchOnly
    Indexing disabled.

The Mac will immediately return to a 99% idle state.

-. --- / .-- .. -. -.. --- .-- ... --..-- / -. --- / -.-. .-. -.--

La voila!

Herman

Saturday, November 1, 2014

Biometric Insecurity

Judge Steven C. Frucci ruled this week that giving police a fingerprint is akin to providing a DNA or handwriting sample or an actual key, which the law permits. A pass code, though, requires the defendant to divulge knowledge, which the law protects against, according to Frucci's written opinion.

This is a very important strike against using Biometrics for security.  Use of biometrics for authentication may be OK, but security not.  A big problem is that most common users confuse the two.

The problem with using fingerprint or voice biometrics is that you leave samples of it everywhere you go. You leave your prints on glasses and door handles.  You leave your voice every time you use a phone and it gets recorded 'for customer satisfaction' reasons.  You leave a picture of your face every time you use a bank machine.  You leave your DNA whenever you use a hair brush. Any semi-savvy crook can lift it and use it against you and worst of all - You Cannot Ever Change It.

Once someone figured out how to impersonate your biometrics, that person can keep doing so forever and you cannot do anything about it, short of dying before he does.

Nowadays, banks and phone companies are starting to use biometrics for identification and authentication.  This is potentially a very bad development.

Tuesday, October 21, 2014

Serial Ports Revisited

We were trying to test a pair of radios with a data loop-back and were again making the same old mistakes and then wondering what the heck is going on. It is just amazing how many times I have sat down and scratched my head with these things - it feels like I never learn or remember!

The mistake we make over and over again is to expect the wrong read/write behaviour from a serial port utility:
  • A serial port is a bidirectional device.
  • A program will grab the device file handle and open the device file either as 'Read', 'Write' or 'Read/Write'.
  • Simple programs like 'cat', 'echo', 'bash' (read, write), 'head', 'tail' and 'of', all open the device file as either 'Read' or 'Write', never 'Read/Write'.
  • Complex programs like 'cutecom', 'minicom', 'screen' and 'netcat', open the device file as 'Read/Write'.
So, one cannot run 'cat' twice on the same port in order to send and receive data, you have to use 'netcat' or 'screen' to do that in one convoluted operation, or you have to make a T cable and run the Rx and Tx wires to two separate serial ports and then you can run 'cat' twice (on the different ports).

Configuration

Ensure that you are a member of the dialout group:
# usermod -a -G dialout username

To configure a serial port you can use either 'screen', 'minicom' or 'stty':
$ screen /dev/ttyUSB0 115200
$ minicom -b 115200 -o -D /dev/ttyUSB0
or
$ stty -F /dev/ttyUSB0 raw
$ stty -F /dev/ttyUSB0 115200


To exit screen, type Control-A k and exit minicom with Control-A x.

Tx and Rx

Then, to send and receive data through the port:

This will not work concurrently.  You cannot open two terminals and run these commands together to see what is transceived in real time:
$ cat txfile > /dev/ttyUSB0
$ cat /dev/ttyUSB0 > rxfile


After the first instance of 'cat' grabbed the file handle to send the file, the second instance cannot open it again to receive the file at the same time - oops...

T Cable Solution

If you make a T cable then you can do this in two terminals:
$ cat txfile > /dev/ttyUSB0
$ cat /dev/ttyUSB1 > rxfile


That will work because each instance of 'cat' uses a separate serial port, but then you got to find three 9 pin connectors and two serial port adaptors, which may not all be available, but the commands are easy to understand.

Echo and Read

The easier way, is to use screen with exec, or minicom with expect, or do character I/O one at a time in bash with echo and read.

If you use read, be sure to set a timeout or it may hang forever.  It is also usually needed to flush any junk from the receive buffer before you try to look for a specific response, and use a sleep statement to allow the response to come back after a command:

echo "Set serial port USB0 to 9600N81"
stty -F /dev/ttyUSB0 raw
stty -F /dev/ttyUSB0 9600
echo

echo Wait for the dust to settle
sleep 1

# Flush
JUNK=""
for i in 1 2 3 4 5; do
  read -r -t1 JUNK < /dev/ttyUSB0

  sleep 0.1
done

# Send LFCR and Read a line
LINE=""
echo -en "/n/r" > /dev/ttyUSB0

sleep 0.1
read -r -t1 LINE < /dev/ttyUSB0

# Flush
JUNK=""
for i in 1 2 3 4 5; do
  read -r -t1 JUNK < /dev/ttyUSB0

  sleep 0.1
done

if [ "$LINE" != "NO CARRIER" ]; then
  echo Communication failure
  exit 1
fi

echo Communication OK

exit 0

Hex and Octal Dump

While I am at it, sometimes it is better to output data in hexadecimal. This can be done with the 'od' (octal dump) program instead of the venerable 'cat':
$ cat txfile | nc < /dev/ttyUSB0 > /dev/ttyUSB0 | od -x

or
$ od -x < /dev/ttyUSB1

or
$ $ od -x < /dev/ttyUSB1 > rxfile

and so on.

A Real Computer

Obviously, you need a real computer to do all this:
http://dilbert.com/dyn/str_strip/000000000/00000000/0000000/000000/20000/1000/000/21021/21021.strip.zoom.gif

The joke comes from here:
http://www.cryptonomicon.com/beginning.html

Serial Port Tips

www.aeronetworks.ca/2015/01/serial-port-io.html
www.aeronetworks.ca/2014/10/serial-ports-revisited.html
www.aeronetworks.ca/2014/01/crcs-and-serial-ports.html
www.aeronetworks.ca/2013/10/serial-port-tricks.html
www.aeronetworks.ca/2013/05/usb-serial-device-with-unknown-ids.html
www.aeronetworks.ca/2015/10/reading-and-parsing-data-from-serial.html
www.aeronetworks.ca/2013/05/compile-moxa-serial-widget-device.html


La voila!

Herman


Monday, October 20, 2014

Printers

A few notes for those new to Linux printing on how to waste perfectly good trees.

FTP

First walk over to the printer and write down the IP address from the little LCD display.

Many network printers have an unsecured FTP server that your company IT is blissfully unaware of (or more likely, they know only True Card Carrying Geeks will use it in a moment of sheer desperation, so they leave it be, even though it can potentially be abused).  If you upload a postscript file to a printer, it will print it immediately - no questions asked.  This works without having anything special installed on your Linux machine.

The process works something like this:

In your application, select Print to File, then save the file as file.ps.  Open a terminal and connect with FTP, then put the file: 

$ ftp 172.22.8.12
Login: [enter]
Password: [enter]
ftp> put file.ps
ftp> bye

La voila!

CUPS with IPP

The CUPS service is maintained by Apple and it works very well indeed.   Usually, it will discover network printers automatically, but unless your company IT named the printers properly, it won't tell you where the printer is and in a large company there may be hundreds of printers all over the world.  If you cannot figure it out, then you can manually configure a printer.

Open a browser and type localhost:631 to open the CUPS management program.

Go to the Administration screen and select Add Printer.  Select the IPP protocol.  For the URL, type for example ipp://172.22.8.12/ipp/

Enter a printer name and location so you can remember which one it is.  Find the printer manufacturer and device driver, for example HP and HP Laserjet 9040 with CUPS and Gutenprint (en).  If you can't find the exact printer model number, try something similar, it usually works - sometimes you just lose a special feature such as duplex printing that nobody ever use anyway, since it always causes paper jams.

Finally, select Maintenance and print a Test Page.

When you experience printer trouble, restart CUPS from the command line with service cups restart  and then go to the management screen again and clear all the stuck print jobs.

Easy as pie.

LPR

When you have CUPS installed, you can also use the lpr program from the command line.  CUPS can print most types of files automatically.  You don't necessarily need to run a specific application to print something - just send the file to CUPS and it will usually figure it out and convert the file to postscript all by itself.

For example to print to the default printer on your machine:

$ lpr -P localhost file.pdf

It also works with text files and even pictures.  You don't need to fire up a PDF reader or Gimp to print.  You can also pipe multiple files and then go and feed the trees and toner into the printer.

You can likewise use lpr to send a file from a new machine with no configuration, to another machine that already has CUPS installed and print via a proxy.  There is always a simple way to make it work.

Saturday, October 18, 2014

Diabetic Foods and Cooking

A few notes on sugar free cooking.

As my doctor put it, I am not diabetic, but I should eat as if I am.

It appears that the most important dietary modification to diabetes and weight control, is to avoid any food that digests rapidly.

At first the list looks daunting: Wheat, potato, rice, alcohol, glucose, sucrose... essentially all common carbohydrates must be avoided - which makes one wonder what is left, since that is about 90% of all the junk on the supermarket shelves!

Oats and Rye

I don't mind going on a caveman diet of meat, salad and nuts, since I'm a committed carnivore already, but wheat bread is curiously addictive and getting over it is not easy.  There are many different kinds of wheat: Spelt, Durham... so be careful that you don't buy an alternative that isn't an alternative at all.

Rye bread is commonly available at bakeries, but it is a little chewy - an automatic consumption limiter.

My wife is an engineer of economics, loves cooking and did a few experiments with rye, oats and barley kernels.  She quickly figured out that it is very easy to make rye and oats flour: Simply chuck the grains into a coffee grinder and press the button - brrrrrrrrrrrrzzzzzzt - done, perfect flour!

The other surprising thing is that when oats flour is used in baking, it doesn't taste like oatmeal porridge as one would expect.  Baked oats confectionery works and tastes the same as wheat bread and cake - probably because of all the other ingredients.  So between oats and rye, we got wheat eliminated easily and she bakes bread, cake, pancakes, strudel - anything - with oats and rye flour.

Barley

Barley makes a perfect alternative to rice.  It is a little different, but sufficiently the same that we don't miss rice at all.

Sucralose, Aspartame, Xilatol and Stevea

For baking, it is important to use a sweetener that doesn't denature at high temperature.  Sucralose is available in boxes as a fluffed up powder that can be used almost 1:1 (more like 1:2, since it is extremely sweet) to replace sugar.

Be careful with diet sodas.  Many people are sensitive to phenylalanine (produced when Aspartame is broken down) and it increases muscle tension.  Too many diet sodas and you will feel creaky as if you are a 100 years old.  If you overdosed on sodas, bear in mind that phenylalanine takes about 14 days to get out of your system again, so be patient, you will eventually be able to turn your head again.  I can handle one diet soda every other day - no more.  Alcohol free beer is much better and I can chug as many of those as I want with no side effects.

Xilatol is used in 'dental' chewing gum.  It is derived from wood.  The only reason I mention this here, is because Xilatol gum will kill a dog - it makes a dog stop breathing.  Don't leave gum lying around where a puppy can get it, or you could become rather unpopular very quickly.

I don't like the taste of Stevea root much, but I cannot imagine life without chocolate...

Life in the Slow Lane

Once you made the above modifications, you will enjoy life in the slow metabolic lane.  Various nuts and little round cheeses is my way of snacking and when we go out, I drink either nealco Zlatý Bažant (Golden Pheasant) or Bavaria (yum), or Diet Cola (yech).

Swimming

The other important thing is exercise - the more the merrier.  I prefer swimming, since gym machines always hurt my hands and I need my fingers for typing.  So I swim about 3km per week - it sure helps living in a hot country, although it is rather chilly today - only 34 Celsius!

Saturday, August 9, 2014

Reversing the Telephone Table

Are you also fed-up with telemarketer calls?  Chris Blasco wrote a nice piece about social engineering a telemarketer into resetting his own phone set: https://plus.google.com/+ChrisBlasko/posts/GzCuzTyUXNq

Being somewhat incredulous after reading that, I researched it myself.  It turns out that it really is that easy to reset a Yealink phone, but resetting a Polycom may require a password and for a Cisco, you need to enter the configuration menu first, so your mileage may vary.

Here is a handy list:
http://www.3cx.com/blog/ip-phone-configuration/factory-reset-your-phone/

This may become a new sport - at least until the telemarketers wizen up.


Saturday, August 2, 2014

Canoeing in Cinque Terre

A Real Canadian always has a canoe at the ready.  We have inflatable canoes stashed with relatives in multiple countries.  These water toys are cheap, relatively light weight (about 25kg) and easy to transport in the boot of a car.  This summer, we took our European Sea Eagle to Northern Italy.

We rented a tiny little apartment in Manarola, roughly in the middle of this picture, next to the old tower, directly above the harbour.

Nowadays, I mostly use my Samsung phone camera - it has some spherical distortion, but the quality and warmth is very pleasing.



Cinque Terre is a crazy place which really should be on your bucket list.  Many of the buildings are from the 15th century, but the craziest building period was in the 19th and 20th.

Note that the best way to get there is by rail from La Spezia.  The railway runs up the coast in an infinite series of tunnels, so it is mostly invisible and doesn't spoil the park.  We went by car and dragging the canoe and luggage between the car park up on the mountain and the village down below, was really hard work.

Pirates ahoi!


We still heard the party on the pirate boat by 4 in the morning.

The view from the canoe, using my waterproof Olympus uTough camera.  The Olympus produces very sharp, but colder photos, which really need to be hue adjusted a bit, but usually I can't be bothered:


The trains only exit the tunnels at the stations.  With only one person in the Sea Eagle, it is a bit wobbly for photos so I ended up with lots of fuzzy ones, but an inflatable has a nice soft ride over the swells - it just bends a bit - same as an air mattress:


...and if you don't have a canoe and don't like trains, take a ferry:


With an inflatable, you should never leave your pump behind!

You can click the pics for a larger view.

Monday, July 21, 2014

PIC16F1708 Macros

So Easy, a Caveman can PIC it

The PIC processors have a small and primitive instruction set.  This makes it easy to learn, but doing anything remotely useful usually requires four or more instructions, liberally sprinkled with BANKSEL instructions, which all make the resulting code hard to read and error prone.

Your Own Development Kit



As you can see above, it is very easy to make a little development kit of your own, using Vero board and a DIP size PIC.  Once things are working, then you can use Eagle schematic and PCB designer to make a tiny surface mount board, or you can just spray the Vero model with conformal coating and stick it into a soap box with a blob of RVT...

Your Own High Level Language

The solution is to make your own high level language of sorts with macros.  The upshot of macros is that if you find a bug in one, then you can fix that bug in many places all at once.  The downside is that debugging complex macros can be hard, since the PICKit3 debugger has a very limited ability to step into a macro.  The best method is to write the code and debug it in a little test program, before turning it into a macro.

Goto in Macros

All high level languages have Goto statements.  Even Ada has it.  The PIC assembly language makes heavy use of Gotos in conditional branch instructions.

One of the annoying things with a macro language is that you cannot use a label inside a macro, since the second time you use the macro, the assembler will complain about a double defined label.  This makes it hard to do loops in a macro, but not impossible.  The trick is to use the goto $ operator:

;loop
        MOVIW FSR0++                ; Copy buffers from bottom upwards
        MOVWI FSR1++
        DECFSZ varlength, F
        GOTO $-3                    ; loop till zero


BASIC Macros

Possibly the most useful statements in BASIC were the PEEK and POKE instructions.  A typical embedded program is full of them.  So if you feel nostalgic, then Macros are an ideal way to get your revenge on Kernighan, Ritchie and Stroustrup.

Here are a few useful macros to get you going:

; Peek and Poke
_PEEK MACRO #register
        BANKSEL #register
        MOVF #register, W
        ENDM

_POKE MACRO #register, #literal
        BANKSEL #register
        MOVLW #literal
        MOVWF #register
        ENDM
       
_SAVE MACRO #register
BANKSEL #register
MOVWF #register
ENDM

_COPY MACRO #regfrom, #regto
        BANKSEL #regfrom
        MOVF #regfrom, W
        BANKSEL #regto
        MOVWF #regto
        ENDM

_ZAP MACRO #register
        BANKSEL #register
        CLRF #register
        ENDM
        
_INC MACRO #register
BANKSEL #register
INCF #register, F
ENDM

_DEC MACRO #register
BANKSEL #register
DECF #register, F
ENDM

; Turn one or more port pins on
_PORTON MACRO   #port, #state, #mask1
        BANKSEL #state
        MOVLW #mask1         ; get the mask
        IORWF #state, W      ; Set bit(s): OR with 1 mask
        MOVWF #state         ; save the state
        BANKSEL #port
        MOVWF #port          ; set the port
        ENDM

; Turn one or more port pins off
_PORTOFF MACRO   #port, #state, #mask0
        BANKSEL #state
        MOVLW #mask0         ; get state
        ANDWF #state, W      ; Clear bit(s): AND with 0 mask
        MOVWF #state         ; save state
        BANKSEL #port
        MOVWF #port          ; set the port
        ENDM

; Toggle one or more port pins
_PORTTOGGLE MACRO    #port, #state, #mask1
        BANKSEL #state
        MOVLW #mask1         ; get 1 mask
        XORWF #state, W      ; toggle bit(s): XOR with 1 mask
        MOVWF #state         ; Save state
        BANKSEL #port
        MOVWF #port          ; Set the port
        ENDM


; Parameter Call Stack
_PUSHALL MACRO #param1, #param2, #param3
        _POKE varstack1, #param1
        _POKE varstack2, #param2
        _POKE varstack3, #param3
        ENDM

_PUSH1 MACRO #param1
        _POKE varstack1, #param1
        ENDM

_PUSH2 MACRO #param2
        _POKE varstack2, #param2
        ENDM

_PUSH3 MACRO #param3
        _POKE varstack3, #param3
        ENDM

_POP1 MACRO
        _PEEK varstack1
        ENDM

_POP2 MACRO
        _PEEK varstack2
        ENDM

_POP3 MACRO
        _PEEK varstack3
        ENDM


; Function Call
_CALL   MACRO #name, #param1, #param2, #param3
        _PUSHALL #param1, #param2, #param3
        PAGESEL #name
        call #name
        ENDM

; Conditional Branches
; Branch if not equal
; Note: Negative statements are harder to understand
_BNEWR  MACRO   #register, #destination
        BANKSEL #register
        SUBWF #register, W
        BTFSS STATUS, Z     ; Test and skip if Z flag is set
        GOTO #destination
        ENDM

_BNERR  MACRO   #register1, #register2, #destination
        BANKSEL #register1
        MOVF #register1, W
        SUBWF #register2, W
        BTFSS STATUS, Z     ; Test and skip if Z flag is set
        GOTO #destination
        ENDM

_BNEWL  MACRO   #literal, #destination
        BANKSEL #destination
        SUBLW #literal
        BTFSS STATUS, Z     ; Test and skip if Z flag is set
        GOTO #destination

        ENDM

_BNERL  MACRO   #register, #literal, #destination
        BANKSEL #register
        MOVLW #literal
        SUBWF #register, W
        BTFSS STATUS, Z     ; Test and skip if Z flag is set
        GOTO #destination
        ENDM

; Branch if equal
; Note: Positive statements are easier to understand
_BEQWR  MACRO   #register, #destination
        BANKSEL #register
        SUBWF #register, W
        BTFSC STATUS, Z     ; Test and skip if Z flag is clear
        GOTO #destination
        ENDM

_BEQRR  MACRO   #register1, #register2, #destination
        BANKSEL #register1
        MOVF #register1, W
        SUBWF #register2, W
        BTFSC STATUS, Z     ; Test and skip if Z flag is clear
        GOTO #destination
        ENDM

_BEQWL  MACRO   #literal, #destination
        BANKSEL #destination
        SUBLW #literal
        BTFSC STATUS, Z     ; Test and skip if Z flag is clear
        GOTO #destination
        ENDM

_BEQRL  MACRO   #register, #literal, #destination
        BANKSEL #register
        MOVLW #literal
        SUBWF #register, W
        BTFSC STATUS, Z     ; Test and skip if Z flag is clear
        GOTO #destination
        ENDM

; Branch if Bit equal
_BBEQRL MACRO #register, #literal, #label
        BANKSEL #register       ; select bank 0
        BTFSC #register, #literal     ; test RCIF receive interrupt
        GOTO #label
        ENDM

; Function call parameter 'stack'
; Obviously this only works one call deep!
group1      UDATA 0x0020
varstack1   res 1               
varstack2   res 1
varstack3   res 1

La Voila!

Sunday, July 6, 2014

PIC16F1708 a Dilly

I always wondered what is a dilly, why would you pick it and what could you possibly do with it in a circus, but those English are crazy - it must be something in the water.

The last time I used a Microchip PIC processor - some time before the dinosaurs in the previous century - there were only a handful of different chips.  Nowadays there are over 300.  A problem with this proliferation is that it is now much more difficult to find relevant information on the exact chip that you want to use and getting started with the infernal things can be very time consuming.

I wanted to use a PIC16F1708, which includes an ADC, DAC and even a couple of Op Amps for anti-aliasing filters, an all in one CODEC chip for an audio interface widget.

Here are a few tips on things that I discovered along the way.

No Power

When trying out the evaluation board I got with the PICkit3, I kept getting the error: 
Target device was not found. You must connect to a target device to use PICkit 3. 

The problem is that there is no power supply on the evaluation target board. The PICkit3 needs to supply the power and it is turned off somewhere, despite the power LED on the probe lighting up.

Try this:
    1. Go to Run > Set Project Configuration > Customize...
    2. In "Categories" window click once on PICkit 3.
    3. In the right side you have "Option Categories" drop down box, click on "Power".
    4. Now check the box for "Power target circuit from PICkit 3".
    5. Choose the "voltage level" from the drop down menu. (My PIC18F45K20 devkit is 3V)

And your target should now power up and be happy.

MPASM Configuration Registers

You must set the Configuration bits in the assembler code at the top of the main file. 

First configure the processor type PIC16F1708 in MPLabX then:
Change Configuration bits in MPLabX in the Configuration Bits window (Window>PIC Memory Views>Configuration Bits). 

Then you can export the settings by right clicking in the window and selecting “Generate Source Code to Output” and copy this code from the Output Window into your code.

First I would put a List command:
 LIST   P=PIC16F1708

Then copy and paste the generated code:

; PIC16F1708 Configuration Bit Settings

; ASM source line config statements

 #include "p16f1708.inc"

; CONFIG1
; __config 0xFFE0
 __CONFIG _CONFIG1, _FOSC_LP & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON
; CONFIG2
; __config 0xFFFF
 __CONFIG _CONFIG2, _WRT_OFF & _PPS1WAY_ON & _ZCDDIS_ON & _PLLEN_ON & _STVREN_ON & _BORV_LO & _LPBOR_OFF & _LVP_ON

Read the PIC data sheet for details, since each of these devices is rather different.

An interesting page layout annoyance to note is that only labels, comments and #include may start in the left-most column.  The __CONFIG macro for example, is indented by one character.

PIC18F45K20 MPASM Example

Here is a LED flasher for the PICkit3 with the PIC18F45K20 development board in MPASM.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; LED flasher
; PIC18F45K20
; Herman Oosthuysen, Copyright Reserved, General Public License (GPL) v2, 2014
; Version 1.00, 7 July 2014
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    LIST   P=PIC18F45K20

; PIC18F45K20 Configuration Bit Settings

#include "p18f45k20.inc"

; CONFIG1H
  CONFIG  FOSC = INTIO7         ; Oscillator Selection bits (Internal oscillator block, port function on RA6 and RA7)
  CONFIG  FCMEN = OFF           ; Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
  CONFIG  IESO = OFF            ; Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

; CONFIG2L
  CONFIG  PWRT = OFF            ; Power-up Timer Enable bit (PWRT disabled)
  CONFIG  BOREN = SBORDIS       ; Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
  CONFIG  BORV = 18             ; Brown Out Reset Voltage bits (VBOR set to 1.8 V nominal)

; CONFIG2H
  CONFIG  WDTEN = OFF           ; Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
  CONFIG  WDTPS = 32768         ; Watchdog Timer Postscale Select bits (1:32768)

; CONFIG3H
  CONFIG  CCP2MX = PORTC        ; CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
  CONFIG  PBADEN = ON           ; PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
  CONFIG  LPT1OSC = OFF         ; Low-Power Timer1 Oscillator Enable bit (Timer1 configured for higher power operation)
  CONFIG  HFOFST = ON           ; HFINTOSC Fast Start-up (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.)
  CONFIG  MCLRE = ON            ; MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)

; CONFIG4L
  CONFIG  STVREN = ON           ; Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
  CONFIG  LVP = OFF             ; Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
  CONFIG  XINST = OFF           ; Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

; CONFIG5L
  CONFIG  CP0 = OFF             ; Code Protection Block 0 (Block 0 (000800-001FFFh) not code-protected)
  CONFIG  CP1 = OFF             ; Code Protection Block 1 (Block 1 (002000-003FFFh) not code-protected)
  CONFIG  CP2 = OFF             ; Code Protection Block 2 (Block 2 (004000-005FFFh) not code-protected)
  CONFIG  CP3 = OFF             ; Code Protection Block 3 (Block 3 (006000-007FFFh) not code-protected)

; CONFIG5H
  CONFIG  CPB = OFF             ; Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
  CONFIG  CPD = OFF             ; Data EEPROM Code Protection bit (Data EEPROM not code-protected)

; CONFIG6L
  CONFIG  WRT0 = OFF            ; Write Protection Block 0 (Block 0 (000800-001FFFh) not write-protected)
  CONFIG  WRT1 = OFF            ; Write Protection Block 1 (Block 1 (002000-003FFFh) not write-protected)
  CONFIG  WRT2 = OFF            ; Write Protection Block 2 (Block 2 (004000-005FFFh) not write-protected)
  CONFIG  WRT3 = OFF            ; Write Protection Block 3 (Block 3 (006000-007FFFh) not write-protected)

; CONFIG6H
  CONFIG  WRTC = OFF            ; Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
  CONFIG  WRTB = OFF            ; Boot Block Write Protection bit (Boot Block (000000-0007FFh) not write-protected)
  CONFIG  WRTD = OFF            ; Data EEPROM Write Protection bit (Data EEPROM not write-protected)

; CONFIG7L
  CONFIG  EBTR0 = OFF           ; Table Read Protection Block 0 (Block 0 (000800-001FFFh) not protected from table reads executed in other blocks)
  CONFIG  EBTR1 = OFF           ; Table Read Protection Block 1 (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks)
  CONFIG  EBTR2 = OFF           ; Table Read Protection Block 2 (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks)
  CONFIG  EBTR3 = OFF           ; Table Read Protection Block 3 (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks)

; CONFIG7H
  CONFIG  EBTRB = OFF           ; Boot Block Table Read Protection bit (Boot Block (000000-0007FFh) not protected from table reads executed in other blocks)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Macros
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Compare file register to constant and jump to destination
;
; if register >= constant
_BGE    MACRO reg, const, dest
        MOVLW const & 0xff
        SUBWF reg, W
        BTFSC STATUS, CARRY
        GOTO dest
        ENDM

; If register == constant
_BEQ    MACRO reg, const, dest
        MOVLW  const & 0xff
        SUBWF  reg, W
        BTFSC  STATUS, Z
        GOTO   dest
        ENDM

; If register <= constant
_BLT    MACRO reg, const, dest
        MOVLW  const & 0xff
        SUBWF  reg, W
        BTFSS  STATUS, C
        GOTO   dest
        ENDM

; If register != constant
_BNE    MACRO reg, const, dest
        MOVLW  const & 0xff
        SUBWF  reg, W
        BTFSS  STATUS, Z
        GOTO   dest
        ENDM


; Swap the accumulator and a file register
_SWAPWF MACRO  reg
        XORFW  reg,F
        XORFW  reg,W
        XORFW  reg,F
        ENDM

; Decrement the accumulator (a readability macro)
_DECW   MACRO
        ADDLW  0xFF       ; Add W to -1
        ENDM




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Variables
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        UDATA 0x0020

delay1  res 1
delay2  res 1


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Vector Table
; Code space = 4kW (0000 - 0FFF)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

START   CODE 0x0000
start
        GLOBAL start
        PAGESEL main
        GOTO main

ISR     CODE 0x0004
isr
        GLOBAL isr
        ; ISR code goes here
        RETFIE

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Main
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MAIN    CODE            ; Linker to place immediately after ISR
main
        GLOBAL    main

        CLRF PORTD
        CLRF TRISD
        CLRF delay1
        CLRF delay2

mainloop:
        BTG PORTD,RD1   ; Toggle PORT D PIN 1 (20)
delay:
        DECFSZ delay1,1 ; Roughly 1 Hz with internal clock
        GOTO delay
        DECFSZ delay2,1
        GOTO delay
        GOTO mainloop

        END
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

This should be a good starting template for assembler jobs with this processor.

PIC16F1708 MPASM Example

Annoyingly, each PIC has a somewhat different instruction set and whatever works on one processor, may not work at all on another.  So when developing something, you got to keep the data sheet open on one screen - a dual screen computer setup is pretty much required to get anything done with the least amount of pain.  A virtual desktop system as in Linux and Mac helps a lot, but two screens are better.

On a PIC, doing anything remotely useful, requires at least 2 instructions and usually more like 4 and each instruction takes at least 2 cycles.   Therefore a machine running at 20 MHz is not as fast as one would think at first glance, but even with a 1 MHz effective 'do something' rate, it is still fast enough to make my head hurt thinking about it.

We used to build frequency hopping radios with 256 kHz processors - the advantage of a low clock speed is low power consumption, which is critical on battery powered equipment.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; PIC16F1708
; Herman Oosthuysen, Copyright Reserved, 2014
; General Public License (GPL) version 2
; Version 0.01, 5 July 2014
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Power
; The PIC16F1708 uses 4 to 6V
; The PICkit3 can power the target, but 5V may not be available on a laptop PC
; Go to Run > Set Project Configuration > Customize...
; In "Categories" window click once on PICkit 3.
; In the right side you have "Option Categories" drop down box, click on "Power".
; Now check the box for "Power target circuit from PICkit 3".
; Choose the "voltage level" from the drop down menu and set it to 4.5V
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Include Files
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    LIST        P=PIC16F1708
    #include    "p16f1708.inc"

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Configuration
; First configure the processor type then do:
; Window>PIC Memory Views>Configuration Bits
; Edit then click "Generate Source Code to Output"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; CONFIG1
; __config 0x17C4
 __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _BOREN_ON & _CLKOUTEN_ON & _IESO_ON & _FCMEN_OFF
; CONFIG2
; __config 0x37FB
 __CONFIG _CONFIG2, _WRT_OFF & _PPS1WAY_OFF & _ZCDDIS_ON & _PLLEN_ON & _STVREN_ON & _BORV_LO & _LPBOR_ON & _LVP_ON


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Macros
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Initialize Clock
_INITOSC MACRO
        BANKSEL OSCCON
        MOVLW B'11111010'   ; Internal oscillator, 16 MHz
        MOVWF OSCCON
        ENDM

; Initialize PORTB
_INITB  MACRO
        BANKSEL PORTB
        CLRF PORTB
        BANKSEL LATB
        CLRF LATB
        BANKSEL ANSELB
        CLRF ANSELB         ; Analogue functions disable = 0
        BANKSEL TRISB       ; Tristate = 1 = Input
        MOVLW B'01110000'   ; Out: B7, In: B6-4
        MOVWF TRISB
        BANKSEL RB7PPS
        MOVLW B'00000'      ; Peripheral Pin Select
        MOVWF RB7PPS        ; LatchB7 = Out
        ENDM


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Variables
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        UDATA   0x20
stateb  res 1                ; LATB status
delay1  res 1                ; Delay LSB
delay2  res 1                ; Delay MSB
        

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Vector Table
; Code space = 4kW (0000 - 0FFF)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
START   CODE 0x0000             ; Reset Vector
start
        GLOBAL start
        PAGESEL main
        GOTO main

ISR     CODE 0x0004             ; Interrupt Service Routine
isr
        GLOBAL isr
        ; ISR code goes here
        RETFIE

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Main Code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MAIN    CODE              ; Main program start vector
main
        GLOBAL    main

        _INITOSC                ; Configure the Clocks
        _INITB                  ; Configure PortB

        BANKSEL stateb          ; Zap the latch variable
        CLRF stateb
        CLRF delay1
        CLRF delay2

flashled
        BANKSEL PORTB           ; Toggle PORT B bit 7 (pin 10)
        MOVLW 0x80              ; set bit 7 in W
        XORWF stateb, 1         ; XOR W with port & store result
        MOVFW stateb            ; get the result again
        MOVWF PORTB             ; Output the latch state to the port latch

delay
        DECFSZ delay1,1         ; Roughly 4 Hz with internal 16 MHz clock
        GOTO delay
        DECFSZ delay2,1
        GOTO delay
        GOTO flashled

        END
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



La voila!